Skip to content
This repository was archived by the owner on Oct 27, 2026. It is now read-only.

Commit a724f60

Browse files
kamathcursoragent
andauthored
ci: open automation PRs with GITHUB_TOKEN instead of Docs Bot (#1198)
* ci: open automation PRs with GITHUB_TOKEN instead of Docs Bot Drop the GitHub App token helper and generate llms.txt in the toolkit docs workflow so automation PRs no longer depend on a second workflow starting from the bot push. Co-authored-by: Anirudh Kamath <kamath@users.noreply.github.com> * fix: avoid Biome noTemplateCurlyInString in workflow test The assertion for github.token used a GitHub Actions expression inside a regular string, which Ultracite flagged as a leftover template placeholder. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Anirudh Kamath <kamath@users.noreply.github.com>
1 parent 407bbe7 commit a724f60

8 files changed

Lines changed: 55 additions & 138 deletions

File tree

‎.github/actions/app-token/action.yml‎

Lines changed: 0 additions & 59 deletions
This file was deleted.

‎.github/workflows/generate-toolkit-docs.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ This workflow regenerates toolkit JSON and opens a PR with the changes. It can b
77
1. Builds the toolkit docs generator.
88
2. Generates toolkit JSON in `toolkit-docs-generator/data/toolkits` using the experience API's public tool catalog, which serves tool definitions and toolkit branding in one anonymous read.
99
3. Syncs integrations sidebar navigation from the generated JSON.
10-
4. Creates or updates a PR on the stable `automation/toolkit-docs` branch if any files changed. Later runs overwrite that open PR with the latest generated docs.
10+
4. Regenerates `public/llms.txt` so the automation PR does not depend on a second workflow.
11+
5. Creates or updates a PR on the stable `automation/toolkit-docs` branch if any files changed. Later runs overwrite that open PR with the latest generated docs.
1112

1213
## Inputs and secrets
1314

1415
Required secrets:
1516

1617
- `ANTHROPIC_API_KEY`
18+
- `OPENAI_API_KEY` (for `llms.txt` summaries)
1719

1820
Optional secrets:
1921

‎.github/workflows/generate-toolkit-docs.yml‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ name: Generate toolkit docs
33
# Flow:
44
# 1) Generate toolkit JSON into toolkit-docs-generator/data/toolkits
55
# 2) Sync integrations sidebar _meta.tsx from toolkit-docs-generator/data/toolkits
6-
# 3) Create or update a PR if changes were produced
6+
# 3) Regenerate public/llms.txt so the automation PR is self-contained
7+
# 4) Create or update a PR if changes were produced
8+
#
9+
# Opens the PR with GITHUB_TOKEN. That does not start other workflows, so this
10+
# job generates llms.txt here instead of depending on llmstxt.yml to fire.
711

812
on:
913
repository_dispatch:
@@ -97,24 +101,20 @@ jobs:
97101
- name: Sync toolkit sidebar navigation
98102
run: pnpm exec tsx toolkit-docs-generator/scripts/sync-toolkit-sidebar.ts --remove-empty-sections=false --verbose
99103

100-
# GITHUB_TOKEN PRs do not start other workflows. Docs Bot is a GitHub
101-
# App, so the opened automation PR still runs Test.
102-
- name: Get app token
103-
id: app-token
104-
uses: ./.github/actions/app-token
105-
with:
106-
app-id: ${{ secrets.DOCS_BOT_CLIENT_ID }}
107-
private-key: ${{ secrets.DOCS_BOT_PRIVATE_KEY }}
104+
# GITHUB_TOKEN PRs do not start llmstxt.yml, so generate the file here.
105+
# The toolkit generator CLI still does not write llms.txt.
106+
- name: Generate llms.txt
107+
run: pnpm llmstxt
108+
env:
109+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
108110

109111
- name: Create pull request
110112
id: cpr
111113
uses: peter-evans/create-pull-request@v7
112114
env:
113115
HUSKY: 0
114116
with:
115-
token: ${{ steps.app-token.outputs.token }}
116-
author: ${{ steps.app-token.outputs.committer }}
117-
committer: ${{ steps.app-token.outputs.committer }}
117+
token: ${{ github.token }}
118118
commit-message: "[AUTO] Adding MCP Servers docs update"
119119
title: "[AUTO] Adding MCP Servers docs update"
120120
body: |
@@ -141,7 +141,7 @@ jobs:
141141
echo "::warning::Could not request review on PR #${{ steps.cpr.outputs.pull-request-number }}: $(cat review-error.log)"
142142
fi
143143
env:
144-
GH_TOKEN: ${{ steps.app-token.outputs.token }}
144+
GH_TOKEN: ${{ github.token }}
145145

146146
- name: Upload generation report
147147
if: always()
@@ -224,7 +224,7 @@ jobs:
224224
225225
if [ "$GENERATION_SUCCEEDED" = "true" ]; then
226226
headline=":warning: Toolkit docs generated, but the workflow failed afterward"
227-
detail="Generation succeeded, so the toolkit JSON is fine. A later workflow step failed — inspect the run to determine whether sidebar sync, PR creation, artifact upload, or Slack notification needs attention."
227+
detail="Generation succeeded, so the toolkit JSON is fine. A later workflow step failed — inspect the run to determine whether sidebar sync, llms.txt generation, PR creation, artifact upload, or Slack notification needs attention."
228228
else
229229
headline=":rotating_light: Toolkit docs generation failed"
230230
detail="The failed run contains the exact file path and validation error."

‎.github/workflows/llmstxt.yml‎

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ jobs:
3737
uses: actions/checkout@v4
3838
with:
3939
ref: ${{ github.event.pull_request.head.ref || github.ref }}
40-
# No credentials to persist: the app token is minted further down,
41-
# once there is something to push. The commit step below supplies it
42-
# to git explicitly.
43-
persist-credentials: false
4440

4541
- name: Install dependencies
4642
run: npm install -g pnpm
@@ -62,38 +58,26 @@ jobs:
6258
echo "has_changes=false" >> $GITHUB_OUTPUT
6359
fi
6460
65-
# GITHUB_TOKEN pushes and PRs do not start other workflows. Docs Bot
66-
# is a GitHub App, so Test still runs on the new SHA.
67-
- name: Get app token
68-
if: steps.check-changes.outputs.has_changes == 'true'
69-
id: app-token
70-
uses: ./.github/actions/app-token
71-
with:
72-
app-id: ${{ secrets.DOCS_BOT_CLIENT_ID }}
73-
private-key: ${{ secrets.DOCS_BOT_PRIVATE_KEY }}
74-
61+
# GITHUB_TOKEN pushes do not start other workflows. That is acceptable
62+
# here: Test already ran on the author's commit, and llms.txt is a
63+
# generated artifact.
7564
- name: Commit changes to PR
7665
if: steps.check-changes.outputs.has_changes == 'true' && github.event_name == 'pull_request'
7766
env:
78-
GH_APP_TOKEN: ${{ steps.app-token.outputs.token }}
79-
USER_NAME: ${{ steps.app-token.outputs.user-name }}
80-
USER_EMAIL: ${{ steps.app-token.outputs.user-email }}
8167
HEAD_REF: ${{ github.event.pull_request.head.ref }}
8268
run: |
83-
git config user.name "$USER_NAME"
84-
git config user.email "$USER_EMAIL"
69+
git config user.name "github-actions[bot]"
70+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
8571
git add public/llms.txt
8672
git commit -m "🤖 Regenerate LLMs.txt"
87-
git push "https://x-access-token:${GH_APP_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "HEAD:${HEAD_REF}"
73+
git push origin "HEAD:${HEAD_REF}"
8874
8975
- name: Create Pull Request (for scheduled/manual runs)
9076
if: steps.check-changes.outputs.has_changes == 'true' && github.event_name != 'pull_request'
9177
id: cpr
9278
uses: peter-evans/create-pull-request@v7
9379
with:
94-
token: ${{ steps.app-token.outputs.token }}
95-
author: ${{ steps.app-token.outputs.committer }}
96-
committer: ${{ steps.app-token.outputs.committer }}
80+
token: ${{ github.token }}
9781
commit-message: Regenerate LLMs.txt and related files
9882
branch: auto-update-llms-txt
9983
delete-branch: true
@@ -107,11 +91,11 @@ jobs:
10791
continue-on-error: true
10892
run: gh pr edit ${{ steps.cpr.outputs.pull-request-number }} --add-reviewer ArcadeAI/engineering-tools-and-dx
10993
env:
110-
GH_TOKEN: ${{ steps.app-token.outputs.token }}
94+
GH_TOKEN: ${{ github.token }}
11195

11296
- name: Enable Pull Request Automerge
11397
if: steps.check-changes.outputs.has_changes == 'true' && github.event_name != 'pull_request' && steps.cpr.outputs.pull-request-number != ''
11498
continue-on-error: true
11599
run: gh pr merge --squash --auto ${{ steps.cpr.outputs.pull-request-number }}
116100
env:
117-
GH_TOKEN: ${{ steps.app-token.outputs.token }}
101+
GH_TOKEN: ${{ github.token }}

‎.github/workflows/update-design-system-dependency.yml‎

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,8 @@ jobs:
4747
pnpm vitest run toolkit-docs-generator/tests/scripts/sync-toolkit-sidebar.test.ts toolkit-docs-generator/tests/sources/oauth-provider-resolver.test.ts
4848
pnpm run build
4949
50-
# GITHUB_TOKEN PRs do not start other workflows. Docs Bot is a GitHub
51-
# App, so the opened automation PR still runs Test.
52-
- name: Get app token
53-
if: steps.check-changes.outputs.has_changes == 'true'
54-
id: app-token
55-
uses: ./.github/actions/app-token
56-
with:
57-
app-id: ${{ secrets.DOCS_BOT_CLIENT_ID }}
58-
private-key: ${{ secrets.DOCS_BOT_PRIVATE_KEY }}
59-
50+
# Compatibility tests and a production build run above, so this workflow
51+
# does not depend on Test starting on the opened PR.
6052
- name: Create pull request
6153
if: steps.check-changes.outputs.has_changes == 'true'
6254
id: cpr
@@ -65,9 +57,7 @@ jobs:
6557
HUSKY: 0
6658
SKIP_HUSKY: 1
6759
with:
68-
token: ${{ steps.app-token.outputs.token }}
69-
author: ${{ steps.app-token.outputs.committer }}
70-
committer: ${{ steps.app-token.outputs.committer }}
60+
token: ${{ github.token }}
7161
commit-message: "chore: update @arcadeai/design-system to latest"
7262
title: "chore: update @arcadeai/design-system to latest"
7363
body: |
@@ -89,4 +79,4 @@ jobs:
8979
continue-on-error: true
9080
run: gh pr edit ${{ steps.cpr.outputs.pull-request-number }} --add-reviewer ArcadeAI/engineering-tools-and-dx
9181
env:
92-
GH_TOKEN: ${{ steps.app-token.outputs.token }}
82+
GH_TOKEN: ${{ github.token }}
Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { readFileSync } from "node:fs";
1+
import { existsSync, readFileSync } from "node:fs";
22
import { join } from "node:path";
33
import { expect, test } from "vitest";
44

@@ -12,22 +12,21 @@ const AUTOMATION_WORKFLOWS = [
1212
] as const;
1313

1414
for (const name of AUTOMATION_WORKFLOWS) {
15-
test(`${name} authenticates PR writes with Docs Bot, not GITHUB_TOKEN`, () => {
15+
test(`${name} opens PRs with GITHUB_TOKEN, not Docs Bot`, () => {
1616
const yaml = readWorkflow(name);
1717

18-
expect(yaml).toContain("uses: ./.github/actions/app-token");
19-
expect(yaml).toContain("secrets.DOCS_BOT_CLIENT_ID");
20-
expect(yaml).toContain("secrets.DOCS_BOT_PRIVATE_KEY");
21-
expect(yaml).toContain("steps.app-token.outputs.token");
22-
expect(yaml).not.toContain("secrets.GITHUB_TOKEN");
18+
expect(yaml).not.toContain("uses: ./.github/actions/app-token");
19+
expect(yaml).not.toContain("DOCS_BOT_CLIENT_ID");
20+
expect(yaml).not.toContain("DOCS_BOT_PRIVATE_KEY");
21+
expect(yaml).not.toContain("create-github-app-token");
22+
expect(yaml).toContain("github.token");
2323
});
2424
}
2525

26-
test("app-token composite action mints a GitHub App installation token", () => {
27-
const action = readFileSync(
28-
join(process.cwd(), ".github", "actions", "app-token", "action.yml"),
29-
"utf-8"
30-
);
31-
32-
expect(action).toContain("actions/create-github-app-token@v2");
26+
test("docs automation no longer ships a GitHub App token action", () => {
27+
expect(
28+
existsSync(
29+
join(process.cwd(), ".github", "actions", "app-token", "action.yml")
30+
)
31+
).toBe(false);
3332
});

‎toolkit-docs-generator/ARCHITECTURE.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,8 @@ flowchart TD
3737
3838
json --> verify["Verify output"]
3939
verify --> sidebar["Sync sidebar _meta.tsx"]
40-
sidebar --> pr["Pull request on<br/>automation/toolkit-docs"]
41-
pr --> llms["llms.txt workflow<br/>regenerates public/llms.txt"]
42-
llms --> pr
40+
sidebar --> llms["pnpm llmstxt<br/>regenerates public/llms.txt"]
41+
llms --> pr["Pull request on<br/>automation/toolkit-docs"]
4342
pr -->|"a human merges"| main["main"]
4443
main --> vercel["Vercel: next build"]
4544
vercel --> pages["Static toolkit pages"]
@@ -64,9 +63,10 @@ files live in this repository and merge like any other change, so a prose edit
6463
reaches the site through the next generation run rather than through a manual
6564
edit of the generated JSON.
6665

67-
Two things the diagram deliberately shows as separate. A second workflow
68-
regenerates `llms.txt` when the data files change, so the generator never writes
69-
it. The sidebar sync writes navigation only, and never touches toolkit JSON.
66+
Two things the diagram deliberately shows as separate. The same workflow
67+
regenerates `llms.txt` after sidebar sync, so the generator never writes it and
68+
the automation PR does not depend on a second workflow starting. The sidebar sync
69+
writes navigation only, and never touches toolkit JSON.
7070

7171
## Core components
7272

‎toolkit-docs-generator/tests/workflows/generate-toolkit-docs.test.ts‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,12 @@ test("porter workflow generates docs and opens a PR", () => {
4848
expect(workflowContents).toContain("HUSKY: 0");
4949
expect(workflowContents).toContain("[AUTO] Adding MCP Servers docs update");
5050
expect(workflowContents).toContain("pull-requests: write");
51-
// GITHUB_TOKEN PRs do not start other workflows, so Test would never run
52-
// on the automation PR. Docs Bot is a GitHub App and avoids that restriction.
53-
expect(workflowContents).toContain("uses: ./.github/actions/app-token");
54-
expect(workflowContents).toContain("steps.app-token.outputs.token");
55-
expect(workflowContents).not.toContain("secrets.GITHUB_TOKEN");
51+
// GITHUB_TOKEN PRs do not start other workflows. Generate llms.txt here
52+
// instead of depending on llmstxt.yml, and open the PR with github.token.
53+
expect(workflowContents).toContain("pnpm llmstxt");
54+
expect(workflowContents).toContain(`token: ${"${"}{ github.token }}`);
55+
expect(workflowContents).not.toContain("uses: ./.github/actions/app-token");
56+
expect(workflowContents).not.toContain("DOCS_BOT");
5657
});
5758

5859
test("porter workflow does not build the docs generator before running it", () => {

0 commit comments

Comments
 (0)