[codex] Add wiki update workflow (#7454)

* Add wiki update workflow

* Update greploop skill automation

* Harden wiki update workflow

* Fix wiki workflow review findings

* Address reviewer workflow feedback

* Harden wiki change validation

* Scope wiki PR lookup to repository

* Address greptile wiki workflow feedback

* Skip wiki link check without changes

* Address greptile read tool feedback
This commit is contained in:
Sipke Schoorstra 2026-05-17 19:32:37 +02:00 committed by GitHub
parent 50f858a8ce
commit 8416ea8af4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 237 additions and 6 deletions

View file

@ -23,7 +23,11 @@ Iteratively fix a PR/MR/CL until Greptile gives a perfect review: 5/5 confidence
## Instructions
### 0. Detect platform
### 0. Delegate execution when invoked by Codex
When Greploop is invoked from Codex and sub-agents are available, the main agent must delegate the actual Greploop execution to a sub-agent by default. Pass along the detected or provided PR/MR/CL identifier, repository/worktree path, current branch, VCS platform, user scope constraints, and any known changed-file intent. The parent agent monitors progress, relays concise status updates, and reports final results. Only run Greploop directly from the parent agent when sub-agents are unavailable or the environment cannot delegate.
### 1. Detect platform
First check for Perforce, then fall back to git remote detection:
@ -43,13 +47,33 @@ fi
For self-hosted GitLab instances whose hostname doesn't contain "gitlab", the user can override by passing `--vcs gitlab` as an input. For Perforce, pass `--vcs perforce`.
### 1. Identify the PR/MR/CL
### 2. Identify or create the PR/MR/CL
**GitHub:**
```bash
gh pr view --json number,headRefName -q '{number: .number, branch: .headRefName}'
if PR_JSON=$(gh pr view --json number,headRefName -q '{number: .number, branch: .headRefName}' 2>/dev/null); then
echo "$PR_JSON"
else
PR_JSON=""
fi
```
If `PR_JSON` is empty because no PR exists for the current branch/worktree, automatically publish a draft PR before starting the loop:
1. Inspect `git status --short` and determine the intended change scope. Do not silently stage unrelated changes; if the worktree is mixed and the intended files are unclear, stop and ask.
2. Ensure the work is on a review branch. If the current branch is missing, protected, default, or unsuitable, create/switch to a `codex/<descriptive-name>` branch.
3. Stage intended changes only, commit if needed, push the branch, and create a draft PR.
```bash
git switch -c codex/<descriptive-name> # only when a review branch is needed
git add <intended-files-only>
git commit -m "<concise change summary>" # only when there are staged changes
git push -u origin HEAD
gh pr create --draft --fill
```
Then continue Greploop against the created PR number.
**GitLab:**
```bash
glab mr view --output json | jq '{iid: .iid, branch: .source_branch}'
@ -73,7 +97,7 @@ Key field differences:
- GitLab: `iid`, `source_branch`, `sha`
- Perforce: changelist number, `P4CLIENT`, shelved files
### 2. Loop
### 3. Loop
Repeat the following cycle. **Max 5 iterations** to avoid runaway loops.
@ -351,8 +375,11 @@ Repeat for each unresolved discussion ID. (GitLab has no batch resolution — lo
#### F. Commit and push / re-shelve
**GitHub/GitLab:**
Before staging, inspect the worktree and keep the write set scoped to Greptile fixes. Do not run `git add -A` when unrelated changes are present; stage only intended files, and stop/ask if scope is ambiguous.
```bash
git add -A
git add <intended-files-only>
git commit -m "address greptile review feedback (greploop iteration N)"
git push
```
@ -371,7 +398,7 @@ sleep 5
Then go back to step **A**.
### 3. Report
### 4. Report
After exiting the loop, summarize:

204
.github/workflows/update-wiki.yml vendored Normal file
View file

@ -0,0 +1,204 @@
name: Update Wiki
on:
workflow_dispatch:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
jobs:
update-wiki:
name: Refresh repo wiki
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: main
fetch-depth: 0
- name: Configure git identity
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Refresh wiki with Claude Code
uses: anthropics/claude-code-action@99ca333651aa9a8becc279065fad21c4ef1c4494 # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
prompt: |
Refresh the repo-local wiki under doc/wiki so it remains accurate for the current Elsa Core codebase.
Scope:
- Edit only files under doc/wiki/.
- Keep the existing wiki structure unless the codebase genuinely needs a new or renamed wiki page.
- Ground every update in the current repository source, tests, specs, and ADRs.
- Preserve relative Markdown links and Mermaid diagrams where useful.
- Do not modify production code, tests, package files, workflows, or non-wiki docs.
- Prefer concise contributor-facing explanations over exhaustive API reference.
Validation:
- Check local Markdown links under doc/wiki before finishing.
- If the wiki is already up to date, leave the worktree unchanged.
claude_args: >-
--allowed-tools
"Edit(doc/wiki/**),Write(doc/wiki/**),Bash(rg:* .),Bash(git diff:*),Bash(git status:*),Bash(ls:* .),Bash(wc:*)"
- name: Verify wiki-only changes
run: |
set -euo pipefail
python3 - <<'PY'
import subprocess
import sys
status = subprocess.run(
["git", "status", "--porcelain=v1", "-z", "--untracked-files=all"],
check=True,
capture_output=True,
).stdout
records = status.split(b"\0")
invalid_paths = []
changed_paths = []
i = 0
while i < len(records):
record = records[i]
if not record:
i += 1
continue
text = record.decode()
code = text[:2]
paths = [text[3:]]
if "R" in code or "C" in code:
i += 1
if i < len(records) and records[i]:
paths.append(records[i].decode())
changed_paths.extend(paths)
invalid_paths.extend(path for path in paths if not path.startswith("doc/wiki/"))
i += 1
if not changed_paths:
print("No wiki changes detected.")
sys.exit(0)
if invalid_paths:
print("The wiki update workflow may only modify files under doc/wiki/.", file=sys.stderr)
print("\n".join(invalid_paths), file=sys.stderr)
sys.exit(1)
print("Wiki-only changes verified.")
PY
if git diff --quiet -- doc/wiki && [ -z "$(git ls-files --others --exclude-standard doc/wiki)" ]; then
echo "No wiki changes detected."
exit 0
fi
- name: Verify local wiki links
run: |
set -euo pipefail
if git diff --quiet -- doc/wiki && [ -z "$(git ls-files --others --exclude-standard doc/wiki)" ]; then
echo "No wiki changes to validate."
exit 0
fi
python3 - <<'PY'
from pathlib import Path
import re
import sys
root = Path(".").resolve()
errors = []
for md in sorted(Path("doc/wiki").rglob("*.md")):
text = md.read_text()
for match in re.finditer(r"\[[^\]]+\]\(([^)]+)\)", text):
target = match.group(1).split("#", 1)[0]
if not target or target.startswith(("http://", "https://", "mailto:")):
continue
path = (md.parent / target).resolve()
try:
path.relative_to(root)
except ValueError:
errors.append((md, target, "outside repo"))
continue
if not path.exists():
errors.append((md, target, "missing"))
if errors:
for md, target, reason in errors:
print(f"{md}: {target} -> {reason}")
sys.exit(1)
print("All local markdown links resolve.")
PY
- name: Open or update wiki refresh pull request
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BASE_BRANCH: main
UPDATE_BRANCH: codex/update-wiki
run: |
set -euo pipefail
if git diff --quiet -- doc/wiki && [ -z "$(git ls-files --others --exclude-standard doc/wiki)" ]; then
echo "No wiki changes to publish."
exit 0
fi
git checkout -B "$UPDATE_BRANCH"
git add doc/wiki
git commit -m "Refresh codebase wiki"
remote_sha="$(git ls-remote --heads origin "$UPDATE_BRANCH" | awk '{print $1}')"
if [ -n "$remote_sha" ]; then
git push --force-with-lease="refs/heads/$UPDATE_BRANCH:$remote_sha" origin "HEAD:$UPDATE_BRANCH"
else
git push origin "HEAD:$UPDATE_BRANCH"
fi
existing_pr="$(gh pr list --repo "$GITHUB_REPOSITORY" --state open --head "$GITHUB_REPOSITORY_OWNER:$UPDATE_BRANCH" --json number --jq '.[0].number // empty')"
body="$(cat <<'MD'
## Summary
Refreshes the repo-local `doc/wiki/` documentation after changes landed on `main`.
## Validation
- Verified the workflow changed only files under `doc/wiki/`.
- Verified all local Markdown links under `doc/wiki/` recursively resolve.
This PR was opened automatically by the Update Wiki workflow.
MD
)"
if [ -n "$existing_pr" ]; then
gh pr edit "$existing_pr" \
--repo "$GITHUB_REPOSITORY" \
--title "[codex] Refresh codebase wiki" \
--body "$body" \
--base "$BASE_BRANCH"
echo "Updated existing PR #$existing_pr."
else
gh pr create \
--repo "$GITHUB_REPOSITORY" \
--title "[codex] Refresh codebase wiki" \
--body "$body" \
--base "$BASE_BRANCH" \
--head "$GITHUB_REPOSITORY_OWNER:$UPDATE_BRANCH"
fi