Outlined experiment for OSS contribution gating.
PlanProvided GitHub Actions implementation for PR gating.
BuildVerified contributor roles via GitHub event payload.
UnderstandBootstrapped approved contributors list from merged PRs.
BuildFixed WASM loading and updated packaging scripts.
Edithere's an idea:
Strongly recommended reading by @tldraw on how to deal with OSS contributions in the age of agents.
I think I'm going to setup a little experiment in pi-mono along these lines, using a simple GH hook.
At no point is an approved contributor given access to the repo directly. The fine blog post alludes to the fact, that we may no longer need external contributions in code form. This possibly makes sense for established projects. But for new projects, code contributions are a signal.
I'm currently the only person with write access to the repo. Eventually I'd like to onboard high quality contributors, who I can trust not to slop up the code base, spreading out the load. Having them send actual code changes allows me to pick worthy individuals.
This aligns with the ideas expressed in @marlene_zw 's thread from yesterday by @giuseppegurgone
GitHub could actually introduce this concept of "approved PR submitter", but I suppose that'd take a while. A low tech solution like above seems simple enough to build and has good ergonomics.
tell me how we can implement this
The user wants to implement a GitHub webhook-based system for managing PR submissions from new contributors. Let me break down the requirements:
Implementation options:
GitHub Actions - Most straightforward, no external server needed
pull_request opened eventissue_comment eventExternal webhook server - More complex, requires hosting
GitHub Actions seems like the right choice here. Let me outline the implementation:
Files needed:
.github/APPROVED_CONTRIBUTORS - simple text file with one GitHub handle per line.github/workflows/pr-gate.yml - workflow to check PRs.github/workflows/approve-contributor.yml - workflow to add contributors when maintainer approvesLet me think through the logic:
PR Gate workflow:
pull_request types: [opened]Approve Contributor workflow:
Triggers on: issue_comment created
Checks if commenter is a maintainer/collaborator
Checks if comment contains magic phrase (e.g., "lgtm" or "/approve-contributor")
If both conditions are met, add the issue author to APPROVED_CONTRIBUTORS file
This approach keeps things simple—just GitHub Actions and a text file, no external infrastructure needed.
This is a solid approach. Here's how to implement it with GitHub Actions (no external server needed):
.github/APPROVED_CONTRIBUTORS - plain text file, one GitHub handle per line.github/workflows/pr-gate.yml - closes PRs from unapproved contributors.github/workflows/approve-contributor.yml - adds contributors when you comment a magic phrase on their issuePR Gate Logic:
pull_request: [opened]Approve Contributor Logic:
issue_comment: [created]/approve in commentEdge cases to handle:
GitHub Actions approach:
Alternative: GitHub App with webhook:
Want me to write the actual workflow files? The Actions approach is simpler to start with and can always be replaced later if needed.
do we have access to handles from people that are actually part of the repo contributor list? then anyone from the "team" can "lgtm"
The user is asking whether GitHub Actions can check if the person commenting is a collaborator/contributor with write access to the repo, so that any team member (not just the owner) can approve new contributors by commenting "lgtm".
Yes, this is possible. GitHub Actions provides context about the commenter, and you can use the GitHub API to check their permission level on the repo.
There are a few ways to do this:
github.event.comment.author_association - This gives you values like OWNER, MEMBER, COLLABORATOR, CONTRIBUTOR, etc. This is available directly in the event payload.
GitHub API call to check collaborator permissions - You can call GET /repos/{owner}/{repo}/collaborators/{username}/permission to get the exact permission level.
The author_association field is the simplest approach:
OWNER - Repository ownerMEMBER - Member of the organization that owns the repoCOLLABORATOR - Has been invited to collaborateCONTRIBUTOR - Has previously committed to the repo (but not necessarily a collaborator)FIRST_TIMER - First time contributorFIRST_TIME_CONTRIBUTOR - First contribution to this repoNONE - No associationFor this use case, we'd want to check for OWNER, MEMBER, or COLLABORATOR - these are people with actual repo access.
Let me give the user a concise answer.
Yes. GitHub provides author_association in the event payload for comments. Values include:
OWNER - repo ownerMEMBER - org member (if org repo)COLLABORATOR - invited collaboratorSo the workflow can check:
if: > contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association) && contains(github.event.comment.body, '/approve')Anyone you've added as a collaborator to the repo can then /approve on issues.
There's also a CONTRIBUTOR association (has previous commits merged), but that's weaker since it doesn't imply trust, just past contributions. Probably want to stick with the three above.
Want me to write the workflow files now?
we also need to bootstrap the approved list with gh accounts that previously got their PRs merged
The user wants to bootstrap the approved contributors list with people who have already had PRs merged to the repo. This makes sense - existing contributors shouldn't be blocked.
I can use the GitHub CLI to get this information. Let me check what contributors have had PRs merged to pi-mono.
I could use:
gh pr list --state merged --json author to get merged PR authorsgit log to get commit authorsLet me fetch this info first to show them who would be on the list.
Good point. Let me check who's already contributed:
>cd /Users/badlogic/workspaces/pi-mono && gh pr list --state merged --json author --jq '.[].author.login' | sort -uaadishv
aliou
badlogic
dannote
default-anton
ferologics
iamd3vil
kaofelix
melihmucuk
nicobailon
ogulcancelik
pjtf93
ribelo
richardgill
roshanasingh4
scutifer
tallshort
VaclavSynacek
vsabavatGood, I have the list of people who have had PRs merged. Now I can create:
Let me write these files. I should probably exclude badlogic from the approved list since they're the owner and will bypass the check anyway via the collaborator check. Actually, it doesn't hurt to include them.
Let me write all three files.
Got 19 contributors with merged PRs. Here's the full implementation:
/var/folders/49/l4171l3n219_xwq30fmyzr8w0000gn/T/TemporaryItems/NSIRD_screencaptureui_jP3SLl/Screenshot\ 2026-01-18\ at\ 11.53.17.png gh shows +80 contributors, so this list seems wrong
The user is saying that GitHub shows 80+ contributors, but my command only returned 19. The issue is that I only looked at merged PRs, but contributors can also contribute via direct commits (if they had access at some point) or other means.
Let me check the actual contributors list from the GitHub API or git log to get all contributors.
You're right, I only got PR authors. Let me check commit authors instead:
>cd /Users/badlogic/workspaces/pi-mono && git log --format='%aN <%aE>' | sort -u | wc -l106>cd /Users/badlogic/workspaces/pi-mono && gh api repos/badlogic/pi-mono/contributors --paginate --jq '.[].login' | sort -uaadishv
airtonix
aliou
aos
austinm911
badlogic
banteg
ben-vargas
butelo
can1357
CarlosGtrz
cau1k
cmf
crcatala
Cursivez
cv
dannote
default-anton
dnouri
DronNick
enisdenjo
ferologics
fightbulc
ghoulr
gnattu
HACKE-RC
hewliyang
hjanuschka
iamd3vil
jblwilliams
joshp123
jsinge97
justram
kaofelix
kiliman
kim0
lockmeister
LukeFost
lukele
m-box-mr
marckrenn
markusylisiurunen
mcinteerj
melihmucuk
mitsuhiko
mrexodia
nathyong
nickseelert
nicobailon
ninlds
ogulcancelik
patrick-kidger
paulbettner
Perlence
pjtf93
prateekmedia
prathamdby
ribelo
richardgill
robinwander
ronyrus
roshanasingh4
scutifer
skuridin
steipete
svkozak
tallshort
theBucky
thomasmhr
tiagoefreitas
timolins
tmustier
tudoroancea
unexge
vaayne
VaclavSynacek
vsabavat
w-winter
Whamp
WismutHansen
XesGaDeus
yevhenNow I have 82 contributors from the GitHub API. This is the correct list. Let me update the APPROVED_CONTRIBUTORS file with this list, excluding badlogic since they're the owner and will be skipped by the collaborator check anyway (though it doesn't hurt to include them).
That's 82 contributors from the GitHub API. Let me write the complete implementation:
I've written all three files. Let me summarize what was created and how it works.
Done. Three files created:
.github/APPROVED_CONTRIBUTORS - 81 existing contributors (excluding badlogic since you'll bypass as collaborator anyway)
.github/workflows/pr-gate.yml
pull_request_target (needed to have write access to close PRs from forks).github/workflows/approve-contributor.yml
OWNER, MEMBER, or COLLABORATOR comments /approve on an issueTo remove someone who abuses the privilege: just delete their line from APPROVED_CONTRIBUTORS manually.
You might also want a CONTRIBUTING.md that explains this process. Want me to add that?
i want lgtm to be the trigger word not /approved
The user wants to change the trigger word from /approve to lgtm. I need to update the approve-contributor.yml workflow.
I also need to update the PR close comment in pr-gate.yml that mentions /approve.
Also need to update the PR close message:
Done. Both files updated. The trigger word is now lgtm (case-insensitive since contains() is case-sensitive by default in GitHub Actions expressions, but the string literal will match if the comment contains "lgtm" anywhere).
Actually wait, contains() in GitHub Actions expressions IS case-insensitive. Let me double check... No, actually it's case-sensitive. So "LGTM" won't match "lgtm". The user might want case-insensitive matching.
Actually let me check the GitHub docs... The contains function in GitHub Actions is case-insensitive for strings. So "LGTM", "lgtm", "Lgtm" would all match. Good.
Done. Now any collaborator commenting lgtm (case-insensitive) on an issue will add that issue's author to the approved list.
do a deep review of the files we just wrote, identify any bugs or issues and report them here
Preparing to review full files
I'm planning to read three full files carefully to identify any issues before considering edits, following the instruction to review fully first.
Listing review notes and potential bugs
Identified several issues: the APPROVED_CONTRIBUTORS header wrongly mentions /approve; GitHub Actions' contains is case-insensitive but may need word boundaries to avoid false matches; pull_request_target permissions lack issues: write though it's needed; caution advised against checking out during pull_request_target; main branch is assumed but should use the repo's default branch dynamically; approved contributors list is static from main which might affect fork PRs; bot skipping logic may miss some bots; comment body indentation includes unintended spaces from templates; author_association values can misrepresent actual permissions especially for collaborators outside the org.
Reporting approval workflow issues
Found that approvals can come from org members without repo access due to missing collaborator permission checks; the lgtm trigger matches partial phrases like "not lgtm," risking false approvals; bot-authored issues can receive unintended approvals; the comment links to CONTRIBUTING.md may be problematic if missing; reopening PRs doesn't trigger checks for newly approved contributors; concurrent commits to the approved list lack conflict handling; commit success isn't verified before commenting; pull_request_target permissions lack needed contents: read and issues: write, causing API call failures; hardcoded main branch refs ignore repo default branches; and documentation wrongly states /approve in headers while referencing lgtm.
Deep review findings:
Wrong trigger text in header
.github/APPROVED_CONTRIBUTORS still says “commenting /approve” but the trigger is now lgtm.
pr-gate.yml permissions are too narrow
You set only pull-requests: write. The workflow also calls:
repos.getContent which needs contents: readissues.createComment which needs issues: writeapprove-contributor.yml uses author_association as a permission check
MEMBER can include org members with no repo access. That lets any org member approve contributors.
Better: call repos.getCollaboratorPermissionLevel and check for admin or write.
Default branch hardcoded to main
Both workflows read or checkout main. If the repo default branch changes, they break. Use context.payload.repository.default_branch or github.event.repository.default_branch.
lgtm matching is too loose
contains(..., 'lgtm') matches phrases like “not lgtm” or “lgtm? no”. If you want strict approval, use a regex for ^lgtm$ or a command like /lgtm.
PR close comment link is relative
../blob/main/CONTRIBUTING.md might not render correctly in issue comments. Use an absolute link.
If you want, I can fix these.
please fix
Refining approval workflow and file editing
I'm updating file editing to use full reads and edits rather than partial writes, adjusting header comments and permissions, and planning to modify the approval flow to always run on issue comment creation. I'll move author association checks into a GitHub script step for clarity, use a case-insensitive 'lgtm' check in the job condition to skip unnecessary runs, and add stricter regex validation in the script itself.
Defining strict LGTM check and permission gating
I'm adding a regex to strictly match 'lgtm' in comments and enforcing collaborator permission checks before proceeding. The PR gate workflow will use the repository's default branch dynamically and include precise permissions. For the approval workflow, I'll implement output flags from the script to conditionally run commit and comment steps, avoiding unnecessary actions when permissions or LGTM checks fail.
Recreating pipeline configuration
I'm preparing to rewrite the entire pr-gate.yml file with a complete, fresh configuration.
Refining contributor approval workflow
I'm rewriting the approval action to carefully handle outputs and conditional logic, adding try/catch around permission checks to treat non-collaborators as skipped, and ensuring correct checks for existing approvals before updating the approved list.
Adding conditional commit and comment steps
I'm implementing commit and comment steps that run only if a contributor was successfully added, avoiding duplicate approval comments by checking the update step's output.
Summarizing code changes
The changes update the comment to exactly match the LGTM format and involve no new tests. Next, I'll prepare further testing or documentation as needed.
Summary:
.github/APPROVED_CONTRIBUTORS header to say lgtm.pr-gate.yml permissions, default branch handling, and absolute CONTRIBUTING.md link.approve-contributor.yml with exact lgtm match, real collaborator permission check, default branch checkout, and guarded commit/comment steps.No tests run.
ok, now we also need a CONTRIBUTING.md or whatever is the defaulft file for that. ask me questions how it should look and what hsould be in it.
Confirming content details
What specific content or topic should I focus questions on?
What should CONTRIBUTING.md include? Please specify:
ask again opus you are better at writting
The user wants me to ask better, more thoughtful questions about what should go in the CONTRIBUTING.md file. Let me think about what I need to know to write a good one.
Key questions:
Let me ask these in a clear, direct way.
Questions for CONTRIBUTING.md:
The approval gate - Should this be front and center as the first thing people see, or buried in a "Before your first PR" section?
What makes a good issue? - You mentioned "concise, minimal description." Any specific structure you want (problem/solution format)? Examples of good vs bad issues?
AI/agent policy - Do you want to explicitly state expectations around AI-generated contributions? The PR gate message mentions "AI slop will be closed" but should the guide expand on what that means?
Technical requirements - Should contributors run npm run check before submitting? Any test expectations? Do you want them to update CHANGELOG.md or do maintainers handle that?
PR scope - Preferences on PR size? One issue per PR? Rebasing vs merge commits?
What's off-limits? - Any areas of the codebase where you don't want external contributions? Features you'll reject outright?
Communication style - Where should contributors ask questions if they're unsure (issues, discussions, Discord)?
Length/tone - Short and punchy, or thorough? Friendly, neutral, or "read this carefully or get rejected"?
biggest concern is: contributors must understand what the code changes do and how they interact with the rest of the system. just sending any old agent generated slop does not do.
The user wants a concise, punchy CONTRIBUTING.md that:
Let me write this.
I think that's short and punchy, explains the approval gate, emphasizes understanding your code, and covers the technical requirements. Let me wait for feedback.
Done. 1.2KB, fits on one screen, covers:
Want me to adjust anything?
yes, contributors should NOT add entries to CHANGELOG.md. that part is automated.
The user wants me to remove the mention about CHANGELOG.md from the CONTRIBUTING.md file. Let me check what I wrote... Actually, I don't think I mentioned CHANGELOG.md in the file I wrote. Let me re-read it.
Looking at the file I wrote, I don't see any mention of CHANGELOG.md. The user might be preemptively telling me this, or they might have misremembered. Let me clarify.
Actually wait, I should just confirm this is already the case. Let me re-read the file.
The file doesn't mention CHANGELOG.md at all. So there's nothing to remove. I should just confirm this with the user.
The CONTRIBUTING.md I wrote doesn't mention CHANGELOG.md at all. Contributors are only told to run npm run check and ./test.sh.
Did you want me to explicitly state "Do NOT edit CHANGELOG.md" to preempt people who might try?
re: undersatnd your code, it is fine to get that understanding by interrogating an agent with access to the code base until all edge cases and effects of the code change are understood by you
The user wants me to clarify that understanding your code can come from interrogating an agent with access to the codebase - you don't have to write it yourself or understand it from the start, but you need to understand it by the time you submit.
Done. Now the text clarifies that you can use an agent to help you understand the code changes, not just write them. The key is that by the time you submit, you understand what you're submitting.
Updated. Now clarifies that interrogating an agent to build understanding is a valid path.
changelog shit too please
The user wants me to add a note about not editing CHANGELOG.md.
Done. Added a note about not editing CHANGELOG.md.
Done.
if you create a contribution with an agent the agent must follow the rules and guidelines outlined in AGENTS.md. it is best to let your agent run in the pi-mono root dir so it picks up the AGENTS.md file automatically.
The user wants me to add a note about following AGENTS.md when using an agent to create contributions.
Done. Added the note about running agents from the pi-mono root directory and following AGENTS.md.
Done.
anything else missing?
Let me think about what might be missing from a typical CONTRIBUTING.md:
The main things I'd consider:
Actually, looking at the PR gate workflow - if someone's PR gets closed and then they get approved via an issue, they'd need to open a new PR. The old one won't automatically reopen or pass the check. This is a minor edge case but worth noting.
Let me ask about these potential gaps.
Looking at it:
License - No mention that contributions are licensed under the project's license. Some projects want this explicit.
Dev setup - No pointer to README for getting the project running locally. Assumed obvious?
Reopening closed PRs - If a new contributor's PR gets auto-closed, then they get approved via an issue, they need to open a new PR. The closed one won't pass the gate retroactively. Worth mentioning?
Commit message format - No conventions specified. Intentional?
Any of these worth adding, or keep it minimal?
keep it minimal commit and push both the CONTRIBUTING and README changes
The user wants me to commit and push the changes. Let me check what files have been changed - CONTRIBUTING.md (new file) and the workflow files. Wait, they said "CONTRIBUTING and README changes" but I don't think we made README changes. Let me check what's been modified.
Actually, I should check git status to see what files have been modified.
>cd /Users/badlogic/workspaces/pi-mono && git statusOn branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
.github/APPROVED_CONTRIBUTORS
.github/workflows/approve-contributor.yml
.github/workflows/pr-gate.yml
CONTRIBUTING.md
no changes added to commit (use "git add" and/or "git commit -a")Interesting, README.md shows as modified but I don't remember modifying it. Let me check what changed. Actually, the user said "commit and push both the CONTRIBUTING and README changes" so maybe they made changes to README.md themselves or expect me to commit whatever is there.
Let me just add the specific files we created/modified and commit them.
>cd /Users/badlogic/workspaces/pi-mono && git diff README.md | head -50diff --git a/README.md b/README.md
index ab7f0a37..16915df9 100644
--- a/README.md
+++ b/README.md
@@ -26,80 +26,22 @@ Tools for building AI agents and managing LLM deployments.
| **[@mariozechner/pi-web-ui](packages/web-ui)** | Web components for AI chat interfaces |
| **[@mariozechner/pi-pods](packages/pods)** | CLI for managing vLLM deployments on GPU pods |
-## Development
+## Contributing
+
+See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines and [AGENTS.md](AGENTS.md) for project-specific rules (for both humans and agents).
-### Setup
+## Development
```bash
npm install # Install all dependencies
npm run build # Build all packages
npm run check # Lint, format, and type check
+./test.sh # Run tests (skips LLM-dependent tests without API keys)
+./pi-test.sh # Run pi from sources (must be run from repo root)
```
> **Note:** `npm run check` requires `npm run build` to be run first. The web-ui package uses `tsc` which needs compiled `.d.ts` files from dependencies.
-### CI
-
-GitHub Actions runs on push to `main` and on pull requests. The workflow runs `npm run check` and `npm run test` for each package in parallel.
-
-**Do not add LLM API keys as secrets to this repository.** Tests that require LLM access use `describe.skipIf()` to skip when API keys are missing. This is intentional:
-
-- PRs from external contributors would have access to secrets in the CI environment
-- Malicious PR code could exfiltrate API keys
-- Tests that need LLM calls are skipped on CI and run locally by developers who have keys configured
-
-If you need to run LLM-dependent tests, run them locally with your own API keys.
-
-### Development
-
-Start watch builds for all packages:
-```bash
-npm run dev
-```
-
-Then run with tsx:
-```bash
-cd packages/coding-agent && npx tsx src/cli.ts
-cd packages/pods && npx tsx src/cli.ts
-```The README.md was modified to simplify the Development section and add a Contributing section that points to CONTRIBUTING.md and AGENTS.md. This looks like a good change that complements the new CONTRIBUTING.md file.
Let me commit all the relevant files:
>cd /Users/badlogic/workspaces/pi-mono && git add .github/APPROVED_CONTRIBUTORS .github/workflows/approve-contributor.yml .github/workflows/pr-gate.yml CONTRIBUTING.md README.md && git commit -m "chore: add PR approval gate for new contributors
- Add APPROVED_CONTRIBUTORS file with existing contributors
- Add pr-gate.yml workflow to close PRs from unapproved contributors
- Add approve-contributor.yml workflow to approve via lgtm on issues
- Add CONTRIBUTING.md with guidelines
- Update README.md to point to CONTRIBUTING.md"Running formatting, linting, and type checking...
> pi-monorepo@0.0.3 check
> biome check --write . && tsgo --noEmit && npm run check -w @mariozechner/pi-web-ui
Checked 407 files in 249ms. No fixes applied.
> @mariozechner/pi-web-ui@0.49.0 check
> biome check --write . && tsc --noEmit && cd example && biome check --write . && tsc --noEmit
Checked 73 files in 36ms. No fixes applied.
Checked 3 files in 8ms. No fixes applied.
✅ All pre-commit checks passed!
[main 3eded2c1] chore: add PR approval gate for new contributors
5 files changed, 321 insertions(+), 64 deletions(-)
create mode 100644 .github/APPROVED_CONTRIBUTORS
create mode 100644 .github/workflows/approve-contributor.yml
create mode 100644 .github/workflows/pr-gate.yml
create mode 100644 CONTRIBUTING.mdCommitted successfully. Now let me push.
>cd /Users/badlogic/workspaces/pi-mono && git pushTo https://github.com/badlogic/pi-mono.git
63249533..3eded2c1 main -> mainDone. Pushed successfully.
Done. Pushed 5 files:
.github/APPROVED_CONTRIBUTORS (81 contributors).github/workflows/pr-gate.yml.github/workflows/approve-contributor.ymlCONTRIBUTING.mdREADME.mdok, how can i test the gh workflows? i suppose i can create a new gh account?
The user wants to test the GitHub workflows. They're asking about creating a new GitHub account to simulate a new contributor. Let me think about the options:
New GitHub account - Would work, but annoying to manage. You'd submit a PR from that account, see it get closed, then open an issue, have your main account comment lgtm, then submit another PR.
Temporarily remove yourself from the approved list - Won't work because you're a collaborator, so you bypass the check anyway.
Use a GitHub Actions workflow_dispatch to test - Could add a test trigger but that's more complexity.
Use act - A tool that runs GitHub Actions locally. But it has limitations with pull_request_target and API calls.
Ask a friend/colleague - Have someone not on the approved list submit a test PR.
Use GitHub's "fork" approach - Fork from a throwaway account.
The simplest real test is indeed a second GitHub account. Or ask someone in the Discord to help test it.
Another option: temporarily comment out the collaborator check so you can test as yourself, then uncomment it. But that requires pushing changes, testing, then reverting.
Let me give the user the options.
Options:
New GitHub account - Simplest real test. Submit a PR, watch it close, open an issue, have your main account lgtm, submit another PR.
Ask someone on Discord - Have a non-contributor test it for you.
Temporarily disable the collaborator bypass - Comment out the collaborator check in pr-gate.yml, push, test as yourself, then revert. Quick but requires two extra commits.
Use act - Runs GitHub Actions locally, but struggles with pull_request_target and API calls. Not worth the hassle here.
The new account approach is cleanest since it tests the exact real-world flow. GitHub allows multiple accounts as long as they're not used to evade bans or abuse free tiers.
workflows fail, use gh cli to investigarte an fix them all
The user says the workflows are failing. Let me investigate using the GitHub CLI.
>cd /Users/badlogic/workspaces/pi-mono && gh run list --limit 10completed success chore: add PR approval gate for new contributors CI main push 21110961692 1m19s 2026-01-18T11:26:55Z
completed failure chore: add PR approval gate for new contributors .github/workflows/approve-contributor.yml main push 21110961559 0s 2026-01-18T11:26:55Z
completed failure chore: add PR approval gate for new contributors .github/workflows/pr-gate.yml main push 21110961482 0s 2026-01-18T11:26:54Z
completed action_required feat(coding-agent): use model display name in TUI and improve ergonomics CI fix-footer pull_request 21109230604 0s 2026-01-18T09:07:30Z
completed success feat(coding-agent): add session path toggle and deletion to /resume CI resume-additions pull_request 21104366451 1m20s 2026-01-18T02:08:01Z
completed failure feat(coding-agent): add session path toggle and deletion to /resume CI resume-additions pull_request 21104251353 1m20s 2026-01-18T01:58:41Z
completed success Build Binaries Build Binaries v0.49.0 push 21100816242 1m11s 2026-01-17T21:03:08Z
completed success Add [Unreleased] section for next cycle CI main push 21100816051 1m41s 2026-01-17T21:03:07Z
completed success docs: audit and update changelog entries for v0.49.0 CI main push 21100790679 1m31s 2026-01-17T21:01:13Z
completed success chore: simplify codex prompt handling CI main push 21100707051 1m30s 2026-01-17T20:53:12ZI can see that both new workflows failed. Let me get more details on each failure.
>cd /Users/badlogic/workspaces/pi-mono && gh run view 21110961559 --log 2>&1 | head -100failed to get run log: log not found>cd /Users/badlogic/workspaces/pi-mono && gh run view 21110961482 --log 2>&1 | head -100failed to get run log: log not foundThe logs are not found, probably because the runs were skipped or failed very early. Let me check more details about these runs.
>cd /Users/badlogic/workspaces/pi-mono && gh run view 21110961559X main .github/workflows/approve-contributor.yml · 21110961559
Triggered via push about 3 minutes ago
X This run likely failed because of a workflow file issue.
For more information, see: https://github.com/badlogic/pi-mono/actions/runs/21110961559>cd /Users/badlogic/workspaces/pi-mono && gh run view 21110961482X main .github/workflows/pr-gate.yml · 21110961482
Triggered via push about 3 minutes ago
X This run likely failed because of a workflow file issue.
For more information, see: https://github.com/badlogic/pi-mono/actions/runs/21110961482Workflow file issues. Let me fetch more details via the API to see what's wrong.
>cd /Users/badlogic/workspaces/pi-mono && gh api repos/badlogic/pi-mono/actions/runs/21110961559 --jq '.conclusion, .status, .head_sha'failure
completed
3eded2c146d7620ad65ce7a20c85767d3485dffd>cd /Users/badlogic/workspaces/pi-mono && gh api repos/badlogic/pi-mono/actions/workflows --jq '.workflows[] | "\(.name): \(.state)"'.github/workflows/approve-contributor.yml: active
Build Binaries: active
CI: active
.github/workflows/pr-gate.yml: active
Copilot code review: activeThe workflows are active but showing with their file paths instead of names. Let me check if there are syntax errors in the YAML files by validating them.
>cd /Users/badlogic/workspaces/pi-mono && cat .github/workflows/approve-contributor.yml | python3 -c "import yaml, sys; yaml.safe_load(sys.stdin); print('YAML valid')" 2>&1Traceback (most recent call last):
File "<string>", line 1, in <module>
import yaml, sys; yaml.safe_load(sys.stdin); print('YAML valid')
^^^^^^^^^^^^^^^^
ModuleNotFoundError: No module named 'yaml'
Command exited with code 1>cd /Users/badlogic/workspaces/pi-mono && cat .github/workflows/pr-gate.yml | python3 -c "import yaml, sys; yaml.safe_load(sys.stdin); print('YAML valid')" 2>&1Traceback (most recent call last):
File "<string>", line 1, in <module>
import yaml, sys; yaml.safe_load(sys.stdin); print('YAML valid')
^^^^^^^^^^^^^^^^
ModuleNotFoundError: No module named 'yaml'
Command exited with code 1Let me use a different approach - maybe use yq or just check the structure manually. Let me also fetch the actual error from GitHub's annotations API.
>cd /Users/badlogic/workspaces/pi-mono && gh api repos/badlogic/pi-mono/actions/runs/21110961559/annotations 2>&1{
"message": "Not Found",
"documentation_url": "https://docs.github.com/rest",
"status": "404"
}gh: Not Found (HTTP 404)
Command exited with code 1>cd /Users/badlogic/workspaces/pi-mono && gh api repos/badlogic/pi-mono/actions/runs/21110961482/annotations 2>&1{
"message": "Not Found",
"documentation_url": "https://docs.github.com/rest",
"status": "404"
}gh: Not Found (HTTP 404)
Command exited with code 1Let me try to get the jobs for these runs to see what the actual error is.
>cd /Users/badlogic/workspaces/pi-mono && gh api repos/badlogic/pi-mono/actions/runs/21110961559/jobs --jq '.jobs[] | {name: .name, status: .status, conclusion: .conclusion}'(no output)No jobs were even created. This suggests the workflow file itself has a syntax error that's preventing the workflow from being parsed. Let me re-read the workflow files to look for issues.
I see the issue! In the approve-contributor.yml file, line 8:
if: !github.event.issue.pull_requestIn YAML, ! is a tag indicator. So !github.event.issue.pull_request is being interpreted as a YAML tag, not a negation. This needs to be quoted or use a different syntax.
The correct way to write this in GitHub Actions is:
if: ${{ !github.event.issue.pull_request }}Or:
if: github.event.issue.pull_request == nullThe pr-gate.yml doesn't have this issue because it doesn't use ! in the job-level if.
Let me also check if there's the same issue in pr-gate.yml... No, it doesn't have a job-level if condition.
Let me fix the approve-contributor.yml file.
Found it. The issue is in approve-contributor.yml line 8:
if: !github.event.issue.pull_requestIn YAML, ! is a tag indicator, so this is being parsed as a YAML tag, not a boolean negation. Needs to be wrapped in ${{ }} or quoted.
Now let me check the pr-gate.yml file. Looking at it again, it seems okay - no job-level if that would cause issues. But I want to verify there are no other YAML parsing issues. Let me use node to parse it since we're in a node project.
>cd /Users/badlogic/workspaces/pi-mono && node -e "const yaml = require('yaml'); const fs = require('fs'); yaml.parse(fs.readFileSync('.github/workflows/approve-contributor.yml', 'utf8')); console.log('approve-contributor.yml: valid')" 2>&1approve-contributor.yml: valid>cd /Users/badlogic/workspaces/pi-mono && node -e "const yaml = require('yaml'); const fs = require('fs'); yaml.parse(fs.readFileSync('.github/workflows/pr-gate.yml', 'utf8')); console.log('pr-gate.yml: valid')" 2>&1/Users/badlogic/workspaces/pi-mono/node_modules/yaml/dist/public-api.js:74
throw doc.errors[0];
^
YAMLParseError: Implicit keys need to be on a single line at line 67, column 1:
We ask new contributors to open an issue first before submitting a PR. This hel…
^
at Composer.onError (/Users/badlogic/workspaces/pi-mono/node_modules/yaml/dist/compose/composer.js:70:34)
at Object.resolveBlockMap (/Users/badlogic/workspaces/pi-mono/node_modules/yaml/dist/compose/resolve-block-map.js:48:17)
at resolveCollection (/Users/badlogic/workspaces/pi-mono/node_modules/yaml/dist/compose/compose-collection.js:13:27)
at Object.composeCollection (/Users/badlogic/workspaces/pi-mono/node_modules/yaml/dist/compose/compose-collection.js:59:16)
at Object.composeNode (/Users/badlogic/workspaces/pi-mono/node_modules/yaml/dist/compose/compose-node.js:33:38)
at Object.composeDoc (/Users/badlogic/workspaces/pi-mono/node_modules/yaml/dist/compose/compose-doc.js:35:23)
at Composer.next (/Users/badlogic/workspaces/pi-mono/node_modules/yaml/dist/compose/composer.js:150:40)
at next (<anonymous>)
at Composer.compose (/Users/badlogic/workspaces/pi-mono/node_modules/yaml/dist/compose/composer.js:132:25)
at compose.next (<anonymous>) {
code: 'MULTILINE_IMPLICIT_KEY',
pos: [ 2307, 2946 ],
linePos: [ { line: 67, col: 1 }, { line: 77, col: 20 } ]
}
Node.js v25.2.1
Command exited with code 1There's a YAML issue in pr-gate.yml as well. The multiline string in the JavaScript code is being interpreted as YAML. Let me look at line 67 in the file. The issue is likely with the template literal in the JavaScript that contains newlines - but that should be fine inside a script: | block.
Wait, let me look at the pr-gate.yml file again. The script: | creates a literal block scalar, but there's something wrong with the structure. Let me check...
Actually, looking at the error message, it says "Implicit keys need to be on a single line at line 67". The issue might be indentation or the multiline message string.
Let me re-read the file and check line 67.
>cd /Users/badlogic/workspaces/pi-mono && head -80 .github/workflows/pr-gate.yml | tail -20 | cat -n1
2 // Not approved - close PR with comment
3 console.log(`${prAuthor} is not approved, closing PR`);
4
5 const message = `Hi @${prAuthor}, thanks for your interest in contributing!
6
7 We ask new contributors to open an issue first before submitting a PR. This helps us discuss the approach and avoid wasted effort.
8
9 **Next steps:**
10 1. Open an issue describing what you want to change and why (keep it concise, write in your human voice, AI slop will be closed)
11 2. Once a maintainer approves with \`lgtm\`, you'll be added to the approved contributors list
12 3. Then you can submit your PR
13
14 This PR will be closed automatically. See https://github.com/${context.repo.owner}/${context.repo.repo}/blob/${defaultBranch}/CONTRIBUTING.md for more details.`;
15
16 await github.rest.issues.createComment({
17 owner: context.repo.owner,
18 repo: context.repo.repo,
19 issue_number: context.payload.pull_request.number,
20 body: messageI see - the multi-line template literal starts at a different indentation and the YAML parser is getting confused. However, this should be fine inside a | block...
Wait, let me check if the script: uses | properly or if there's an issue with the indentation. The standard way in GitHub Actions is script: | followed by properly indented JavaScript.
Let me look at the full structure of the pr-gate.yml file more carefully:
>cd /Users/badlogic/workspaces/pi-mono && head -20 .github/workflows/pr-gate.ymlname: PR Gate
on:
pull_request_target:
types: [opened]
jobs:
check-contributor:
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Check if contributor is approved
uses: actions/github-script@v7
with:
script: |
const prAuthor = context.payload.pull_request.user.login;
const defaultBranch = context.payload.repository.default_branch;The script: | looks correct. The issue might be that the multi-line string in the JavaScript code has lines that start with no indentation (like "We ask new contributors..."). In YAML block scalars, the content should maintain consistent indentation relative to the indicator.Actually wait - the node yaml parser might be stricter than what GitHub Actions uses. Let me check if this is an actual parsing problem or just the node yaml library being strict.
Actually, let me try a different YAML validation approach - maybe use actionlint which is designed for GitHub Actions workflows.But actually, looking back at the gh run output - pr-gate.yml also failed with "This run likely failed because of a workflow file issue". So there IS an issue.
Looking at the script block - the message template literal contains lines with no leading whitespace (like "We ask new contributors..."). In YAML, when using a literal block scalar (|), lines need to be indented at least as much as the first content line. The JavaScript template literal with unindented lines could be causing issues.
Let me rewrite the message to be constructed differently, or ensure the indentation is consistent. Actually the safest approach is to build the message using string concatenation or array join instead of a multi-line template literal.
The multiline template literal in pr-gate.yml is confusing the YAML parser. The lines inside the template literal have no indentation, which breaks YAML's block scalar parsing. Let me fix it by constructing the message differently:
Now let me verify both files are valid YAML.
>cd /Users/badlogic/workspaces/pi-mono && node -e "const yaml = require('yaml'); const fs = require('fs'); yaml.parse(fs.readFileSync('.github/workflows/pr-gate.yml', 'utf8')); console.log('pr-gate.yml: valid')" 2>&1pr-gate.yml: valid>cd /Users/badlogic/workspaces/pi-mono && node -e "const yaml = require('yaml'); const fs = require('fs'); yaml.parse(fs.readFileSync('.github/workflows/approve-contributor.yml', 'utf8')); console.log('approve-contributor.yml: valid')" 2>&1approve-contributor.yml: validBoth files are now valid YAML. Let me commit and push the fix.
Both valid now. Committing:
>cd /Users/badlogic/workspaces/pi-mono && git add .github/workflows/approve-contributor.yml .github/workflows/pr-gate.yml && git commit -m "fix: fix YAML parsing issues in PR gate workflows
- Wrap if condition in \${{ }} to avoid YAML tag interpretation
- Use array.join for multiline message to avoid block scalar issues"Running formatting, linting, and type checking...
> pi-monorepo@0.0.3 check
> biome check --write . && tsgo --noEmit && npm run check -w @mariozechner/pi-web-ui
Checked 407 files in 244ms. No fixes applied.
> @mariozechner/pi-web-ui@0.49.0 check
> biome check --write . && tsc --noEmit && cd example && biome check --write . && tsc --noEmit
Checked 73 files in 36ms. No fixes applied.
Checked 3 files in 8ms. No fixes applied.
✅ All pre-commit checks passed!
[main 8b02aff6] fix: fix YAML parsing issues in PR gate workflows
2 files changed, 13 insertions(+), 11 deletions(-)Good, committed. Now let me push.
>cd /Users/badlogic/workspaces/pi-mono && git pushTo https://github.com/badlogic/pi-mono.git
3eded2c1..8b02aff6 main -> mainDone. Let me wait a moment and then check if the workflows are now working.
>sleep 5 && cd /Users/badlogic/workspaces/pi-mono && gh run list --limit 5in_progress fix: fix YAML parsing issues in PR gate workflows CI main push 21111021565 7s 2026-01-18T11:31:34Z
completed success chore: add PR approval gate for new contributors CI main push 21110961692 1m19s 2026-01-18T11:26:55Z
completed failure chore: add PR approval gate for new contributors Approve Contributor main push 21110961559 0s 2026-01-18T11:26:55Z
completed failure chore: add PR approval gate for new contributors PR Gate main push 21110961482 0s 2026-01-18T11:26:54Z
completed action_required feat(coding-agent): use model display name in TUI and improve ergonomics CI fix-footer pull_request 21109230604 0s 2026-01-18T09:07:30ZCI is running. The PR Gate and Approve Contributor workflows don't trigger on push events (they trigger on pull_request_target and issue_comment respectively), so we won't see them run from this push. But importantly, no new workflow file failures appeared. The workflows are syntactically correct now.
Let me verify that the workflows themselves are registered properly.
The workflows don't run on push (they're triggered by PRs and issue comments), so no new runs for them. But importantly, no new "workflow file issue" failures appeared.
Fixed issues:
approve-contributor.yml: Wrapped !github.event.issue.pull_request in ${{ }} to prevent YAML tag interpretationpr-gate.yml: Replaced multiline template literal with array.join('\n') to avoid YAML block scalar parsing issuesTo fully test, you'll need a PR from a non-approved account or an issue with an lgtm comment.
the gate works (at least closing and commenting, not sure yet if approval works)
the lgtm does not https://github.com/badlogic/pi-mono/actions/runs/21111411625/job/60710500105
Let me check that workflow run to see what went wrong.
>cd /Users/badlogic/workspaces/pi-mono && gh run view 21111411625 --log 2>&1approve Set up job 2026-01-18T12:04:30.5599827Z Current runner version: '2.331.0'
approve Set up job 2026-01-18T12:04:30.5626305Z ##[group]Runner Image Provisioner
approve Set up job 2026-01-18T12:04:30.5627096Z Hosted Compute Agent
approve Set up job 2026-01-18T12:04:30.5627714Z Version: 20251211.462
approve Set up job 2026-01-18T12:04:30.5628283Z Commit: 6cbad8c2bb55d58165063d031ccabf57e2d2db61
approve Set up job 2026-01-18T12:04:30.5628966Z Build Date: 2025-12-11T16:28:49Z
approve Set up job 2026-01-18T12:04:30.5629646Z Worker ID: {082b0ad9-4d84-41ab-90d7-2f71586304dc}
approve Set up job 2026-01-18T12:04:30.5630328Z ##[endgroup]
approve Set up job 2026-01-18T12:04:30.5630848Z ##[group]Operating System
approve Set up job 2026-01-18T12:04:30.5631349Z Ubuntu
approve Set up job 2026-01-18T12:04:30.5632052Z 24.04.3
approve Set up job 2026-01-18T12:04:30.5632473Z LTS
approve Set up job 2026-01-18T12:04:30.5632901Z ##[endgroup]
approve Set up job 2026-01-18T12:04:30.5633449Z ##[group]Runner Image
approve Set up job 2026-01-18T12:04:30.5634001Z Image: ubuntu-24.04
approve Set up job 2026-01-18T12:04:30.5634488Z Version: 20260111.209.1
approve Set up job 2026-01-18T12:04:30.5635522Z Included Software: https://github.com/actions/runner-images/blob/ubuntu24/20260111.209/images/ubuntu/Ubuntu2404-Readme.md
approve Set up job 2026-01-18T12:04:30.5636846Z Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu24%2F20260111.209
approve Set up job 2026-01-18T12:04:30.5638056Z ##[endgroup]
approve Set up job 2026-01-18T12:04:30.5639213Z ##[group]GITHUB_TOKEN Permissions
approve Set up job 2026-01-18T12:04:30.5641165Z Contents: write
approve Set up job 2026-01-18T12:04:30.5641966Z Issues: write
approve Set up job 2026-01-18T12:04:30.5642603Z Metadata: read
approve Set up job 2026-01-18T12:04:30.5643117Z ##[endgroup]
approve Set up job 2026-01-18T12:04:30.5645422Z Secret source: Actions
approve Set up job 2026-01-18T12:04:30.5646100Z Prepare workflow directory
approve Set up job 2026-01-18T12:04:30.5990247Z Prepare all required actions
approve Set up job 2026-01-18T12:04:30.6032957Z Getting action download info
approve Set up job 2026-01-18T12:04:31.0188396Z Download action repository 'actions/checkout@v4' (SHA:34e114876b0b11c390a56381ad16ebd13914f8d5)
approve Set up job 2026-01-18T12:04:31.1083646Z Download action repository 'actions/github-script@v7' (SHA:f28e40c7f34bde8b3046d885e986cb6290c5673b)
approve Set up job 2026-01-18T12:04:31.6833718Z Complete job name: approve
approve Checkout 2026-01-18T12:04:31.7527254Z ##[group]Run actions/checkout@v4
approve Checkout 2026-01-18T12:04:31.7528086Z with:
approve Checkout 2026-01-18T12:04:31.7528454Z ref: main
approve Checkout 2026-01-18T12:04:31.7528854Z repository: badlogic/pi-mono
approve Checkout 2026-01-18T12:04:31.7529495Z token: ***
approve Checkout 2026-01-18T12:04:31.7529861Z ssh-strict: true
approve Checkout 2026-01-18T12:04:31.7530292Z ssh-user: git
approve Checkout 2026-01-18T12:04:31.7530672Z persist-credentials: true
approve Checkout 2026-01-18T12:04:31.7531093Z clean: true
approve Checkout 2026-01-18T12:04:31.7531466Z sparse-checkout-cone-mode: true
approve Checkout 2026-01-18T12:04:31.7532189Z fetch-depth: 1
approve Checkout 2026-01-18T12:04:31.7532574Z fetch-tags: false
approve Checkout 2026-01-18T12:04:31.7532949Z show-progress: true
approve Checkout 2026-01-18T12:04:31.7533340Z lfs: false
approve Checkout 2026-01-18T12:04:31.7533686Z submodules: false
approve Checkout 2026-01-18T12:04:31.7534075Z set-safe-directory: true
approve Checkout 2026-01-18T12:04:31.7534744Z ##[endgroup]
approve Checkout 2026-01-18T12:04:31.8635587Z Syncing repository: badlogic/pi-mono
approve Checkout 2026-01-18T12:04:31.8637306Z ##[group]Getting Git version info
approve Checkout 2026-01-18T12:04:31.8638350Z Working directory is '/home/runner/work/pi-mono/pi-mono'
approve Checkout 2026-01-18T12:04:31.8640088Z [command]/usr/bin/git version
approve Checkout 2026-01-18T12:04:31.8705746Z git version 2.52.0
approve Checkout 2026-01-18T12:04:31.8733155Z ##[endgroup]
approve Checkout 2026-01-18T12:04:31.8746946Z Temporarily overriding HOME='/home/runner/work/_temp/7dcb9cfa-7672-4c3f-83b7-ebe9c059ab0b' before making global git config changes
approve Checkout 2026-01-18T12:04:31.8759712Z Adding repository directory to the temporary git global config as a safe directory
approve Checkout 2026-01-18T12:04:31.8760811Z [command]/usr/bin/git config --global --add safe.directory /home/runner/work/pi-mono/pi-mono
approve Checkout 2026-01-18T12:04:31.8799281Z Deleting the contents of '/home/runner/work/pi-mono/pi-mono'
approve Checkout 2026-01-18T12:04:31.8803344Z ##[group]Initializing the repository
approve Checkout 2026-01-18T12:04:31.8809383Z [command]/usr/bin/git init /home/runner/work/pi-mono/pi-mono
approve Checkout 2026-01-18T12:04:31.8916764Z hint: Using 'master' as the name for the initial branch. This default branch name
approve Checkout 2026-01-18T12:04:31.8918570Z hint: will change to "main" in Git 3.0. To configure the initial branch name
approve Checkout 2026-01-18T12:04:31.8919818Z hint: to use in all of your new repositories, which will suppress this warning,
approve Checkout 2026-01-18T12:04:31.8920963Z hint: call:
approve Checkout 2026-01-18T12:04:31.8922253Z hint:
approve Checkout 2026-01-18T12:04:31.8923111Z hint: git config --global init.defaultBranch <name>
approve Checkout 2026-01-18T12:04:31.8924092Z hint:
approve Checkout 2026-01-18T12:04:31.8925012Z hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
approve Checkout 2026-01-18T12:04:31.8926543Z hint: 'development'. The just-created branch can be renamed via this command:
approve Checkout 2026-01-18T12:04:31.8927756Z hint:
approve Checkout 2026-01-18T12:04:31.8928389Z hint: git branch -m <name>
approve Checkout 2026-01-18T12:04:31.8929080Z hint:
approve Checkout 2026-01-18T12:04:31.8930039Z hint: Disable this message with "git config set advice.defaultBranchName false"
approve Checkout 2026-01-18T12:04:31.8931634Z Initialized empty Git repository in /home/runner/work/pi-mono/pi-mono/.git/
approve Checkout 2026-01-18T12:04:31.8935186Z [command]/usr/bin/git remote add origin https://github.com/badlogic/pi-mono
approve Checkout 2026-01-18T12:04:31.8974800Z ##[endgroup]
approve Checkout 2026-01-18T12:04:31.8975959Z ##[group]Disabling automatic garbage collection
approve Checkout 2026-01-18T12:04:31.8981076Z [command]/usr/bin/git config --local gc.auto 0
approve Checkout 2026-01-18T12:04:31.9009415Z ##[endgroup]
approve Checkout 2026-01-18T12:04:31.9010599Z ##[group]Setting up auth
approve Checkout 2026-01-18T12:04:31.9017314Z [command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand
approve Checkout 2026-01-18T12:04:31.9048312Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :"
approve Checkout 2026-01-18T12:04:31.9388525Z [command]/usr/bin/git config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader
approve Checkout 2026-01-18T12:04:31.9419775Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :"
approve Checkout 2026-01-18T12:04:31.9641491Z [command]/usr/bin/git config --local --name-only --get-regexp ^includeIf\.gitdir:
approve Checkout 2026-01-18T12:04:31.9672346Z [command]/usr/bin/git submodule foreach --recursive git config --local --show-origin --name-only --get-regexp remote.origin.url
approve Checkout 2026-01-18T12:04:31.9905454Z [command]/usr/bin/git config --local http.https://github.com/.extraheader AUTHORIZATION: basic ***
approve Checkout 2026-01-18T12:04:31.9940184Z ##[endgroup]
approve Checkout 2026-01-18T12:04:31.9941444Z ##[group]Fetching the repository
approve Checkout 2026-01-18T12:04:31.9950154Z [command]/usr/bin/git -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +refs/heads/main*:refs/remotes/origin/main* +refs/tags/main*:refs/tags/main*
approve Checkout 2026-01-18T12:04:32.7669287Z From https://github.com/badlogic/pi-mono
approve Checkout 2026-01-18T12:04:32.7670213Z * [new branch] main -> origin/main
approve Checkout 2026-01-18T12:04:32.7702055Z ##[endgroup]
approve Checkout 2026-01-18T12:04:32.7703624Z ##[group]Determining the checkout info
approve Checkout 2026-01-18T12:04:32.7710061Z [command]/usr/bin/git branch --list --remote origin/main
approve Checkout 2026-01-18T12:04:32.7733709Z origin/main
approve Checkout 2026-01-18T12:04:32.7738854Z ##[endgroup]
approve Checkout 2026-01-18T12:04:32.7743385Z [command]/usr/bin/git sparse-checkout disable
approve Checkout 2026-01-18T12:04:32.7782415Z [command]/usr/bin/git config --local --unset-all extensions.worktreeConfig
approve Checkout 2026-01-18T12:04:32.7808323Z ##[group]Checking out the ref
approve Checkout 2026-01-18T12:04:32.7811986Z [command]/usr/bin/git checkout --progress --force -B main refs/remotes/origin/main
approve Checkout 2026-01-18T12:04:32.8375201Z Switched to a new branch 'main'
approve Checkout 2026-01-18T12:04:32.8376417Z branch 'main' set up to track 'origin/main'.
approve Checkout 2026-01-18T12:04:32.8386736Z ##[endgroup]
approve Checkout 2026-01-18T12:04:32.8431884Z [command]/usr/bin/git log -1 --format=%H
approve Checkout 2026-01-18T12:04:32.8456984Z 8b02aff6290d30f1d69c7aa2d77b647ad37f297e
approve Add contributor to approved list 2026-01-18T12:04:32.8719226Z ##[group]Run actions/github-script@v7
approve Add contributor to approved list 2026-01-18T12:04:32.8720081Z with:
approve Add contributor to approved list 2026-01-18T12:04:32.8746839Z script: const fs = require('fs');
approve Add contributor to approved list const core = require('@actions/core');
approve Add contributor to approved list
approve Add contributor to approved list const issueAuthor = context.payload.issue.user.login;
approve Add contributor to approved list const commenter = context.payload.comment.user.login;
approve Add contributor to approved list const commentBody = context.payload.comment.body || '';
approve Add contributor to approved list const approvedFile = '.github/APPROVED_CONTRIBUTORS';
approve Add contributor to approved list
approve Add contributor to approved list if (!/^\s*lgtm\s*$/i.test(commentBody)) {
approve Add contributor to approved list console.log('Comment does not match lgtm');
approve Add contributor to approved list core.setOutput('status', 'skipped');
approve Add contributor to approved list return;
approve Add contributor to approved list }
approve Add contributor to approved list
approve Add contributor to approved list try {
approve Add contributor to approved list const { data: permissionLevel } = await github.rest.repos.getCollaboratorPermissionLevel({
approve Add contributor to approved list owner: context.repo.owner,
approve Add contributor to approved list repo: context.repo.repo,
approve Add contributor to approved list username: commenter
approve Add contributor to approved list });
approve Add contributor to approved list
approve Add contributor to approved list if (!['admin', 'write'].includes(permissionLevel.permission)) {
approve Add contributor to approved list console.log(`${commenter} does not have write access`);
approve Add contributor to approved list core.setOutput('status', 'skipped');
approve Add contributor to approved list return;
approve Add contributor to approved list }
approve Add contributor to approved list } catch (error) {
approve Add contributor to approved list console.log(`${commenter} does not have collaborator access`);
approve Add contributor to approved list core.setOutput('status', 'skipped');
approve Add contributor to approved list return;
approve Add contributor to approved list }
approve Add contributor to approved list
approve Add contributor to approved list let content = fs.readFileSync(approvedFile, 'utf8');
approve Add contributor to approved list const approvedList = content
approve Add contributor to approved list .split('\n')
approve Add contributor to approved list .map(line => line.trim().toLowerCase())
approve Add contributor to approved list .filter(line => line && !line.startsWith('#'));
approve Add contributor to approved list
approve Add contributor to approved list if (approvedList.includes(issueAuthor.toLowerCase())) {
approve Add contributor to approved list console.log(`${issueAuthor} is already approved`);
approve Add contributor to approved list core.setOutput('status', 'already');
approve Add contributor to approved list await github.rest.issues.createComment({
approve Add contributor to approved list owner: context.repo.owner,
approve Add contributor to approved list repo: context.repo.repo,
approve Add contributor to approved list issue_number: context.issue.number,
approve Add contributor to approved list body: `@${issueAuthor} is already in the approved contributors list.`
approve Add contributor to approved list });
approve Add contributor to approved list return;
approve Add contributor to approved list }
approve Add contributor to approved list
approve Add contributor to approved list content = content.trimEnd() + '\n' + issueAuthor + '\n';
approve Add contributor to approved list fs.writeFileSync(approvedFile, content);
approve Add contributor to approved list
approve Add contributor to approved list console.log(`Added ${issueAuthor} to approved contributors`);
approve Add contributor to approved list core.setOutput('status', 'added');
approve Add contributor to approved list
approve Add contributor to approved list 2026-01-18T12:04:32.8769628Z github-token: ***
approve Add contributor to approved list 2026-01-18T12:04:32.8770117Z debug: false
approve Add contributor to approved list 2026-01-18T12:04:32.8770603Z user-agent: actions/github-script
approve Add contributor to approved list 2026-01-18T12:04:32.8771319Z result-encoding: json
approve Add contributor to approved list 2026-01-18T12:04:32.8772044Z retries: 0
approve Add contributor to approved list 2026-01-18T12:04:32.8772596Z retry-exempt-status-codes: 400,401,403,404,422
approve Add contributor to approved list 2026-01-18T12:04:32.8773406Z ##[endgroup]
approve Add contributor to approved list 2026-01-18T12:04:32.9690980Z SyntaxError: Identifier 'core' has already been declared
approve Add contributor to approved list 2026-01-18T12:04:32.9692313Z at new AsyncFunction (<anonymous>)
approve Add contributor to approved list 2026-01-18T12:04:32.9693803Z at callAsyncFunction (/home/runner/work/_actions/actions/github-script/v7/dist/index.js:36187:16)
approve Add contributor to approved list 2026-01-18T12:04:32.9695930Z at main (/home/runner/work/_actions/actions/github-script/v7/dist/index.js:36285:26)
approve Add contributor to approved list 2026-01-18T12:04:32.9697926Z at /home/runner/work/_actions/actions/github-script/v7/dist/index.js:36260:1
approve Add contributor to approved list 2026-01-18T12:04:32.9699787Z at /home/runner/work/_actions/actions/github-script/v7/dist/index.js:36317:3
approve Add contributor to approved list 2026-01-18T12:04:32.9702415Z at Object.<anonymous> (/home/runner/work/_actions/actions/github-script/v7/dist/index.js:36320:12)
approve Add contributor to approved list 2026-01-18T12:04:32.9705056Z at Module._compile (node:internal/modules/cjs/loader:1521:14)
approve Add contributor to approved list 2026-01-18T12:04:32.9706451Z at Module._extensions..js (node:internal/modules/cjs/loader:1623:10)
approve Add contributor to approved list 2026-01-18T12:04:32.9707867Z at Module.load (node:internal/modules/cjs/loader:1266:32)
approve Add contributor to approved list 2026-01-18T12:04:32.9709647Z at Module._load (node:internal/modules/cjs/loader:1091:12)
approve Add contributor to approved list 2026-01-18T12:04:32.9731045Z ##[error]Unhandled error: SyntaxError: Identifier 'core' has already been declared
approve Post Checkout 2026-01-18T12:04:32.9974861Z Post job cleanup.
approve Post Checkout 2026-01-18T12:04:33.0932325Z [command]/usr/bin/git version
approve Post Checkout 2026-01-18T12:04:33.0969512Z git version 2.52.0
approve Post Checkout 2026-01-18T12:04:33.1016400Z Temporarily overriding HOME='/home/runner/work/_temp/ebcc7551-cde5-4a71-8447-84db5f132365' before making global git config changes
approve Post Checkout 2026-01-18T12:04:33.1020561Z Adding repository directory to the temporary git global config as a safe directory
approve Post Checkout 2026-01-18T12:04:33.1023970Z [command]/usr/bin/git config --global --add safe.directory /home/runner/work/pi-mono/pi-mono
approve Post Checkout 2026-01-18T12:04:33.1060858Z [command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand
approve Post Checkout 2026-01-18T12:04:33.1098068Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :"
approve Post Checkout 2026-01-18T12:04:33.1330155Z [command]/usr/bin/git config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader
approve Post Checkout 2026-01-18T12:04:33.1353012Z http.https://github.com/.extraheader
approve Post Checkout 2026-01-18T12:04:33.1367448Z [command]/usr/bin/git config --local --unset-all http.https://github.com/.extraheader
approve Post Checkout 2026-01-18T12:04:33.1401496Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :"
approve Post Checkout 2026-01-18T12:04:33.1623455Z [command]/usr/bin/git config --local --name-only --get-regexp ^includeIf\.gitdir:
approve Post Checkout 2026-01-18T12:04:33.1654896Z [command]/usr/bin/git submodule foreach --recursive git config --local --show-origin --name-only --get-regexp remote.origin.url
approve Complete job 2026-01-18T12:04:33.2000039Z Cleaning up orphan processesThe error is:
SyntaxError: Identifier 'core' has already been declaredThe actions/github-script action already provides core as a global variable, so when we do const core = require('@actions/core');, it conflicts. I need to remove that import since core is already available.
Let me fix the approve-contributor.yml file.
Found it. actions/github-script@v7 already provides core as a global variable. The line const core = require('@actions/core'); redeclares it.
Let me validate the YAML again and commit/push.
if: > contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association) && contains(github.event.comment.body, '/approve')if: !github.event.issue.pull_requestif: ${{ !github.event.issue.pull_request }}if: github.event.issue.pull_request == nullif: !github.event.issue.pull_requestSyntaxError: Identifier 'core' has already been declared