Compare commits

...

14 Commits

3 changed files with 116 additions and 16 deletions
+17 -9
View File
@@ -1,9 +1,16 @@
name: Codex Bot
description: Run Codex CLI for approved Gitea issue/PR automation
name: Bot agents
description: Run a coding agent for approved Gitea issue/PR automation
inputs:
gitea-token:
bot-type:
description: Which bot to run, either `codex` or `claude`
required: true
gitea-token:
description: Gitea access token for API calls and pushes
required: true
bot-token:
description: API key or token for the selected bot
required: false
runs:
using: composite
@@ -14,15 +21,16 @@ runs:
run: |
apt-get update
apt-get install -y --no-install-recommends gettext-base jq ansifilter
npm install -g @openai/codex
- name: Run Codex Bot
npm install -g @openai/codex @anthropic-ai/claude-code
- name: Run bot
shell: bash
run: bash "${ACTION_PATH}/scripts/run-codex.sh"
run: bash "${ACTION_PATH}/scripts/run-${{ inputs.bot-type }}.sh"
env:
ACTION_PATH: ${{ gitea.action_path }}
GITEA_API_URL: ${{ gitea.api_url }}
GITEA_REPOSITORY: ${{ gitea.repository }}
GITEA_TOKEN: ${{ inputs.gitea-token }}
ISSUE_INDEX: ${{ gitea.event.issue.number }}
COMMENT_BODY: ${{ gitea.event.comment.body }}
BOT_TOKEN: ${{ inputs.bot-token }}
EVENT_NAME: ${{ gitea.event_name }}
ISSUE_INDEX: ${{ gitea.event.issue.number || gitea.event.pull_request.number }}
COMMENT: ${{ toJSON(gitea.event.comment || gitea.event.review) }}
+50 -7
View File
@@ -1,21 +1,56 @@
You are Codex running inside Gitea Actions.
You are a coding agent running inside Gitea Actions.
First read `.codex-bot/context.md`. Treat the triggering comment body below as
the user's exact instruction.
Do not post a final issue comment yourself; your final response is posted
automatically. Post additional comments only when needed for PR updates,
screenshots, questions, or blockers.
Keep every issue and PR comment extremely short and simple. Strongly prefer
nested bulleted lists for readability. Report only the outcome and tests; omit
explanations, summaries, and pleasantries.
This is a single non-interactive run. The process exits the moment your final
response ends, so background monitors, scheduled wake-ups, and queued tasks
never resume. Never promise future action and never claim to be waiting on a
notification.
For a `pull_request` event, review the newly opened PR without changing code. If
changes are needed, include `@bot` in the final response with instructions to
fix the findings. Otherwise, do not mention `@bot`. For UI changes, check that
the result is aligned, clean, and pixel-perfect, and that included screenshots
prove the intended result was achieved.
For an `issue_comment` or `pull_request_review_comment` event, treat the `body`
in the triggering comment payload below as the user's exact instruction.
Install missing tools yourself when needed, including Rust, uv, Node, Deno, or
system packages.
Before modifying or pushing code, check for another active automation run that
may modify the same target branch or work on the same issue or pull request. If
one exists, wait for it to finish before making changes. Wait inside this run
with a foreground shell loop that polls and prints a line every 30 seconds, for
as long as it takes, even hours; a silent process is killed as a zombie. Use a
blocking `sleep` even if your tool instructions discourage it, and ignore any
advice to wait by scheduling a callback instead. Never report being blocked by
another run; always wait it out and complete the task before responding.
Afterwards, pull the latest branch state before pushing. Skip this check when no
code changes are needed.
Prefer minimal, correct changes. Run relevant checks or tests if practical.
Treat code changes as a request to create a pull request. If a prior Codex pull
Treat code changes as a request to create a pull request. If a prior bot pull
request already exists for this issue, update that same pull request instead of
creating a new one. Finish by reporting what changed and what tests ran. Wait
creating a new one. When you create a pull request, include `@bot` in its body
and ask it to review the pull request. This is required for every pull request
you create. Finish by briefly reporting what changed and what tests ran. Wait
for Gitea Actions CI to complete, and fix any failures.
# Comment body
If you modify UI code, include Playwright screenshots in your PR or issue
comments. If you need UI clarification, ask with screenshots when helpful.
# Comment payload
```
${COMMENT_BODY}
${COMMENT}
```
# Full issue comment history
@@ -23,3 +58,11 @@ ${COMMENT_BODY}
```
${ISSUE_COMMENTS}
```
# Gitea context
- Event: `${EVENT_NAME}`
- API URL: `${GITEA_API_URL}`
- Repository: `${GITEA_REPOSITORY}`
- Issue index: `${ISSUE_INDEX}`
- Use the `GITEA_TOKEN` environment variable for authenticated Gitea API calls.
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
set -euo pipefail
git config --global user.name bot
git config --global user.email noreply@capsulizers.com
COMMENT_FILE="$(mktemp)"
post_comment() {
COMMENT_JSON="$(jq -n --rawfile body "${COMMENT_FILE}" '{body: $body}')"
curl --fail-with-body --silent --show-error \
-X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
--data "${COMMENT_JSON}" \
"${GITEA_API_URL}/repos/${GITEA_REPOSITORY}/issues/${ISSUE_INDEX}/comments"
}
if [ -z "${BOT_TOKEN:-}" ]; then
echo 'Run `claude setup-token` locally and set the `bot-token` action input.' > "${COMMENT_FILE}"
post_comment
exit 1
fi
export CLAUDE_CODE_OAUTH_TOKEN="${BOT_TOKEN}"
export ISSUE_COMMENTS="$(
curl --fail-with-body --silent --show-error \
-H "Authorization: token ${GITEA_TOKEN}" \
"${GITEA_API_URL}/repos/${GITEA_REPOSITORY}/issues/${ISSUE_INDEX}/comments?limit=100" \
| jq -r '.[] | "## " + .user.login + " at " + .created_at + "\n\n" + .body + "\n"'
)"
FINAL_PROMPT="$(envsubst < "${ACTION_PATH}/scripts/prompt.md")"
# Claude refuses --dangerously-skip-permissions as root outside a sandbox.
export IS_SANDBOX=1
# Stream events so the runner sees output and does not kill the job as a zombie.
STREAM_FILE="$(mktemp)"
claude --print --dangerously-skip-permissions \
--output-format stream-json --verbose "${FINAL_PROMPT}" \
| tee "${STREAM_FILE}" \
| jq -r --unbuffered '.message.content[]? | .thinking // .text // .name // empty'
jq -r 'select(.type == "result") | .result // ("Bot failed: " + .subtype)' "${STREAM_FILE}" \
| ansifilter > "${COMMENT_FILE}"
post_comment