Skip to content

Collect consent in the chat widget before the first message #20517

Collect consent in the chat widget before the first message

Collect consent in the chat widget before the first message #20517

Workflow file for this run

# Claude Code Workflow
#
# Runs Claude Code against issues and PR/issue conversations in two modes:
# - Scheduled/manual (find-work + scheduled jobs): picks the oldest open
# issue labelled `claude` that doesn't already have an open PR, and
# implements its next unchecked task.
# - Event-driven (claude job): responds to an `@claude` mention in an issue
# comment, PR review comment, or PR review, or to an issue being labelled
# `claude`.
#
# Triggered on: daily schedule, manual dispatch, `@claude` mention (issue
# comment, PR review comment, or PR review), or issue labelled `claude`
# Requirements: ANTHROPIC_API_KEY secret must be configured
#
# Notes:
# - Applies the `claude` label to PRs it opens when instructed by the prompt
# (the scheduled/manual mode aims to create one PR per completed task).
# - Runs are grouped per issue/PR (`cancel-in-progress: false`), so a
# second trigger for the same issue or PR waits for the in-progress run
# to finish rather than replacing it.
# - The `claude` job has no actor/permission gate of its own — it relies on
# claude-code-action's built-in check that the triggering user has write
# access to this repo. A mention or review from anyone without write
# access (most fork PR authors included) fails the "Run Claude Code" step
# with "Action failed with error: User does not have write access on this
# repository" rather than being silently skipped.
name: Claude Code
on:
schedule:
- cron: '0 2 * * *' # Daily at 2am UTC — picks up next incremental task
workflow_dispatch:
inputs:
issue_number:
description: 'Specific issue number to work on (optional)'
required: false
type: string
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [labeled]
pull_request_review:
types: [submitted]
concurrency:
group: >-
claude-${{
github.event_name == 'schedule' && 'scheduled' ||
github.event_name == 'workflow_dispatch' && format('dispatch-{0}', inputs.issue_number) ||
github.event.issue.number ||
github.event.pull_request.number ||
github.run_id
}}
cancel-in-progress: false
# Restrict default permissions — jobs override as needed
permissions:
contents: read
issues: read
pull-requests: read
jobs:
# ── Scheduled / manual: find the next issue to work on ──
find-work:
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
outputs:
issue_number: ${{ steps.find.outputs.issue_number }}
issue_body: ${{ steps.find.outputs.issue_body }}
issue_title: ${{ steps.find.outputs.issue_title }}
steps:
# Audit only: records egress without blocking. Flip to `block` plus an
# `allowed-endpoints` list once the recorded traffic looks stable.
- name: Harden the runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: Find oldest labeled issue without an open PR
id: find
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INPUT_ISSUE_NUMBER: ${{ inputs.issue_number }}
run: |
REPO="${{ github.repository }}"
# Get head branch names of all open PRs with the label
OPEN_PR_BRANCHES=$(gh pr list --repo "$REPO" --label "claude" --state open --json headRefName --jq '.[].headRefName')
if [ -n "$INPUT_ISSUE_NUMBER" ]; then
# Manual dispatch: use the specified issue but check for existing PR
ISSUE_NUMBER="$INPUT_ISSUE_NUMBER"
if echo "$OPEN_PR_BRANCHES" | grep -q "^claude/${ISSUE_NUMBER}-"; then
echo "::notice::Issue #$ISSUE_NUMBER already has an open PR, skipping"
exit 0
fi
else
# Scheduled: find the oldest issue that doesn't already have an open PR
ISSUES=$(gh issue list --repo "$REPO" --label "claude" --state open --json number,createdAt --jq 'sort_by(.createdAt) | .[].number')
ISSUE_NUMBER=""
for CANDIDATE in $ISSUES; do
if ! echo "$OPEN_PR_BRANCHES" | grep -q "^claude/${CANDIDATE}-"; then
ISSUE_NUMBER="$CANDIDATE"
break
fi
echo "::notice::Issue #$CANDIDATE already has an open PR, skipping"
done
fi
if [ -z "$ISSUE_NUMBER" ]; then
echo "::notice::No eligible issues found"
exit 0
fi
echo "issue_number=$ISSUE_NUMBER" >> "$GITHUB_OUTPUT"
# Fetch issue details
ISSUE_DATA=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json title,body)
ISSUE_TITLE=$(echo "$ISSUE_DATA" | jq -r '.title')
ISSUE_BODY=$(echo "$ISSUE_DATA" | jq -r '.body')
DELIMITER="ghadelim_$(openssl rand -hex 8)"
{
echo "issue_title<<$DELIMITER"
echo "$ISSUE_TITLE"
echo "$DELIMITER"
echo "issue_body<<$DELIMITER"
echo "$ISSUE_BODY"
echo "$DELIMITER"
} >> "$GITHUB_OUTPUT"
# ── Scheduled / manual: implement the next task on the found issue ──
scheduled:
needs: find-work
if: needs.find-work.outputs.issue_number != ''
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres_password
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
redis:
image: redis
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
env:
DJANGO_DATABASE_USER: postgres
DJANGO_DATABASE_PASSWORD: postgres_password
SECRET_KEY: secret-test-key
steps:
# Audit only: records egress without blocking. Flip to `block` plus an
# `allowed-endpoints` list once the recorded traffic looks stable.
- name: Harden the runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@v7
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: '3.13'
- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Install Python dependencies
run: |
uv venv
uv sync --locked --dev
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
- uses: pnpm/action-setup@v6.0.10
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: 24.x
cache: 'pnpm'
- name: Install Node dependencies
run: pnpm install --frozen-lockfile
- name: Create branch
id: branch
run: |
BRANCH_NAME="claude/${{ needs.find-work.outputs.issue_number }}-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$BRANCH_NAME"
echo "branch_name=$BRANCH_NAME" >> "$GITHUB_OUTPUT"
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1.0.206
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
You are working on an incremental project tracked in issue #${{ needs.find-work.outputs.issue_number }}.
## Issue Title
${{ needs.find-work.outputs.issue_title }}
## Issue Content
${{ needs.find-work.outputs.issue_body }}
## Instructions
1. Read the issue and identify the first unchecked task (- [ ]) that is not marked as blocked
2. Implement that task, making git commits as you go
3. Run lint, type checks, and tests, fix any issues:
- Python lint: ruff check --fix && ruff format
- Python type check: uv run ty check apps/
- JS/TS lint: pnpm run lint
- Python test: pytest path/to/file.py -v
4. Push the changes you've made to GitHub and create a PR with the 'claude' label.
5. After completing the task, update the issue using gh issue edit to:
- Check off the completed task (change - [ ] to - [x])
- Add any learnings to the ## Learnings section (create if needed)
6. If you cannot complete the task, mark it as blocked (add "blocked:" prefix to the task)
7. Add a comment to the issue summarizing what you did
If all tasks are complete or blocked, comment on the issue explaining the status.
claude_args: '--allowedTools "Bash(pnpm run lint:*),Bash(pnpm run type-check:*),Bash(pnpm run build:*),Bash(ruff check:*),Bash(ruff format:*),Bash(ty check:*),Bash(uv run ty:*),Bash(uv run ruff:*),Bash(uv run pytest:*),Bash(pytest:*),Bash(uv run --no-project zensical build:*),Bash(git add:*),Bash(git commit:*),Bash(git push:*),Bash(git rm:*),Bash(git checkout:*),Bash(git switch:*),Bash(git status:*),Bash(git diff:*),Bash(gh pr create:*),Bash(gh pr edit:*),Bash(gh api:*),Bash(gh issue edit:*),Bash(gh issue comment:*),Bash(ls:*),Bash(grep:*),Bash(sort:*),Bash(tail:*),Grep,Glob,Read,Write,Edit"'
# ── Event-driven: respond to @claude mentions, issue label ──
claude:
if: |
github.event_name != 'schedule' && github.event_name != 'workflow_dispatch' && (
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && github.event.action == 'labeled' && github.event.label.name == 'claude')
)
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres_password
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
redis:
image: redis
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
env:
DJANGO_DATABASE_USER: postgres
DJANGO_DATABASE_PASSWORD: postgres_password
SECRET_KEY: secret-test-key
steps:
# Audit only: records egress without blocking. Flip to `block` plus an
# `allowed-endpoints` list once the recorded traffic looks stable.
- name: Harden the runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@v7
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: '3.13'
- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Install Python dependencies
run: |
uv venv
uv sync --locked --dev
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
- uses: pnpm/action-setup@v6.0.10
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: 24.x
cache: 'pnpm'
- name: Install Node dependencies
run: pnpm install --frozen-lockfile
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1.0.206
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
branch_prefix: "claude/"
claude_args: |
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(pnpm run lint:*),Bash(pnpm run type-check:*),Bash(pnpm run build:*),Bash(ruff check:*),Bash(ruff format:*),Bash(ty check:*),Bash(uv run ty:*),Bash(uv run ruff:*),Bash(uv run pytest:*),Bash(pytest:*),Bash(git add:*),Bash(git commit:*),Bash(git push:*),Bash(git checkout:*),Bash(git switch:*),Bash(git status:*),Bash(git diff:*),Bash(git branch:*),Bash(gh pr create:*),Bash(gh pr edit:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh api:*),Bash(gh issue comment:*),Bash(gh issue edit:*),Read,Write,Edit"