diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..6222bb3 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,14 @@ +## Summary + + + +## Testing + +- [ ] `pytest` +- [ ] `ruff check src tests` + +## Agent review + +PRs from `cursor/*` branches automatically post a kickoff comment that triggers **@codex** and **@claude**. Resolve the review debate in-thread before merging. + +If kickoff did not run, use **Actions → Agent review kickoff → Run workflow** with this PR number. diff --git a/.github/workflows/agent-pr-review-kickoff.yml b/.github/workflows/agent-pr-review-kickoff.yml new file mode 100644 index 0000000..415a6f5 --- /dev/null +++ b/.github/workflows/agent-pr-review-kickoff.yml @@ -0,0 +1,125 @@ +# When Cursor (or other agents) open a PR, automatically start the Codex ↔ Claude review debate. +# Manual rerun: Actions → "Agent review kickoff" → Run workflow → enter PR number. + +name: Agent review kickoff + +on: + pull_request: + types: [opened, ready_for_review, reopened] + workflow_dispatch: + inputs: + pr_number: + description: PR number to kick off agent review on + required: true + type: number + +permissions: + contents: read + pull-requests: write + issues: write + +concurrency: + group: agent-review-kickoff-${{ github.event.pull_request.number || inputs.pr_number }} + cancel-in-progress: false + +jobs: + kickoff: + runs-on: ubuntu-latest + steps: + - name: Resolve pull request number + id: pr + uses: actions/github-script@v7 + with: + script: | + const prNumber = + context.payload.pull_request?.number ?? + Number(context.payload.inputs?.pr_number); + if (!prNumber || Number.isNaN(prNumber)) { + core.setFailed("No pull request number available"); + return; + } + core.setOutput("number", String(prNumber)); + + - name: Load pull request + id: load + uses: actions/github-script@v7 + with: + script: | + const pr = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: Number("${{ steps.pr.outputs.number }}"), + }); + core.setOutput("head_ref", pr.data.head.ref); + core.setOutput("is_draft", String(pr.data.draft)); + core.setOutput("html_url", pr.data.html_url); + + - name: Decide whether to kick off + id: gate + uses: actions/github-script@v7 + with: + script: | + const headRef = "${{ steps.load.outputs.head_ref }}"; + const isManual = context.eventName === "workflow_dispatch"; + const isAgentBranch = headRef.startsWith("cursor/"); + const shouldRun = isManual || isAgentBranch; + core.setOutput("should_run", shouldRun ? "true" : "false"); + if (!shouldRun) { + core.info(`Skipping kickoff: head ref ${headRef} is not an agent branch`); + } + + - name: Skip — not an agent PR + if: steps.gate.outputs.should_run != 'true' + run: echo "No agent-review kickoff needed for this PR." + + - name: Post agent review kickoff comment + if: steps.gate.outputs.should_run == 'true' + uses: actions/github-script@v7 + with: + script: | + const marker = ""; + const prNumber = Number("${{ steps.pr.outputs.number }}"); + const isDraft = "${{ steps.load.outputs.is_draft }}" === "true"; + const prUrl = "${{ steps.load.outputs.html_url }}"; + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + per_page: 100, + }); + if (comments.some((c) => c.body?.includes(marker))) { + core.info("Kickoff comment already exists; skipping duplicate."); + return; + } + + const draftNote = isDraft + ? "\n\n> **Note:** This PR is still a **draft**. Mark it ready for review when you want CodeRabbit and full CI gates to run; Codex and Claude can still respond below.\n" + : ""; + + const body = `${marker} +## Agent review debate + +This pull request was opened by an automated agent (**Cursor Cloud Agent**). Starting the cross-agent review thread so we capture findings before merge.${draftNote} + +@codex review + +@claude Please review this PR and engage with Codex's findings — agree or disagree on each P0/P1, note missing risks, and keep the debate in this thread before merge. + +**Review focus (everybot)** +- Slack scopes, token handling, and Socket Mode deployment +- \`/idea\` channel gating and message handler edge cases +- Tests and docs staying aligned with \`docs/SETUP.md\` + +Repo guidance: see [\`AGENTS.md\`](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/AGENTS.md). + +--- +Automated by [.github/workflows/agent-pr-review-kickoff.yml](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/.github/workflows/agent-pr-review-kickoff.yml) · PR: ${prUrl} +`; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body, + }); diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..4084228 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,16 @@ +# Agent instructions (everybot) + +## Review guidelines + +When reviewing pull requests for this repository: + +- Treat missing or overly broad Slack OAuth scopes as **P1**. +- Flag any code that logs or persists Slack tokens, message content with PII, or user IDs without a documented retention policy. +- Verify `/idea` channel gating cannot be bypassed unintentionally (wrong channel, empty `CREATIVE_CHANNEL_ID`, race on `message` events). +- Socket Mode and long-running processes must document how deploys restart the bot without duplicating event handling. +- Prefer small, testable pure functions for parsing and validation; handlers should stay thin. +- Documentation changes in `docs/SETUP.md` must match actual env vars and slash command names in code. + +## Cross-agent debate + +After **Codex** posts a review, **Claude** should explicitly agree or disagree with each P0/P1 item and propose concrete alternatives. **Cursor** (author) should address or rebut findings in-thread before merge. diff --git a/README.md b/README.md index efd7542..4bd41b5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # everybot -all slack bot channel + +Slack bot for Scalinity creative and ideas channels. + +## Agent PR reviews + +Pull requests on `cursor/*` branches automatically receive a kickoff comment that triggers **@codex review** and **@claude** for an in-thread debate before merge. See `AGENTS.md` and `.github/workflows/agent-pr-review-kickoff.yml`. + +To manually kick off review on an existing PR: **Actions → Agent review kickoff → Run workflow**.