Evolution #1003
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Evolution | |
| on: | |
| schedule: | |
| - cron: '0 * * * *' # every hour (sponsor gate in evolve.sh controls actual frequency) | |
| workflow_dispatch: # manual trigger for testing | |
| concurrency: | |
| group: evolution | |
| cancel-in-progress: false # queue new runs, don't cancel in-progress ones | |
| permissions: | |
| contents: write | |
| issues: write | |
| jobs: | |
| evolve: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 150 | |
| steps: | |
| - name: Generate bot token | |
| id: bot-token | |
| uses: actions/create-github-app-token@v1 | |
| with: | |
| app-id: ${{ secrets.APP_ID }} | |
| private-key: ${{ secrets.APP_PRIVATE_KEY }} | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ steps.bot-token.outputs.token }} | |
| fetch-depth: 50 | |
| persist-credentials: false | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy | |
| - name: Setup GitHub CLI | |
| run: gh auth status | |
| env: | |
| GH_TOKEN: ${{ steps.bot-token.outputs.token }} | |
| GH_PAT: ${{ secrets.GH_PAT }} | |
| - name: Cache cargo | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} | |
| restore-keys: ${{ runner.os }}-cargo- | |
| # Install RTK (Rust Token Killer — github.com/rtk-ai/rtk) for CLI output | |
| # compression. yoyo's `maybe_prefix_rtk()` auto-prefixes supported | |
| # commands when `rtk` is on PATH; falls back to native compressor in | |
| # `src/format/output.rs` if absent. Especially leveraged by | |
| # analyze-trajectory which fetches large `gh run view --log-failed` | |
| # artifacts. Fail-soft: install failure does not block the session. | |
| - name: Install RTK (output compression) | |
| continue-on-error: true | |
| run: | | |
| if ! command -v rtk &>/dev/null; then | |
| curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh || true | |
| echo "$HOME/.local/bin" >> "$GITHUB_PATH" | |
| fi | |
| # Verify (non-fatal — agent has a native fallback) | |
| export PATH="$HOME/.local/bin:$PATH" | |
| rtk --version || echo "RTK install failed; agent will use native compressor" | |
| # Install xurl for the x-research skill. Token (X_BEARER_TOKEN) is wired | |
| # into the agent run step's env block, where the skill actually executes. | |
| # Fail-soft: install failure leaves the skill unavailable but does not | |
| # block the session. The skill body falls back to "auth not configured; | |
| # skill unavailable this session" when neither xurl+~/.xurl nor | |
| # X_BEARER_TOKEN are present. | |
| - name: Install xurl (x-research skill) | |
| continue-on-error: true | |
| run: | | |
| if ! command -v xurl &>/dev/null; then | |
| cargo install xurl | |
| fi | |
| xurl --version || echo "::warning::xurl install failed; x-research skill will be unavailable" | |
| - name: Detect bot identity | |
| id: bot-info | |
| run: | | |
| SLUG="${{ steps.bot-token.outputs.app-slug }}" | |
| if [ -z "$SLUG" ]; then | |
| echo "::error::GitHub App slug is empty. Check that your GitHub App is configured correctly." | |
| exit 1 | |
| fi | |
| echo "slug=${SLUG}" >> "$GITHUB_OUTPUT" | |
| echo "login=${SLUG}[bot]" >> "$GITHUB_OUTPUT" | |
| echo "email=${SLUG}[bot]@users.noreply.github.com" >> "$GITHUB_OUTPUT" | |
| - name: Configure git | |
| run: | | |
| git config user.name "${{ steps.bot-info.outputs.login }}" | |
| git config user.email "${{ steps.bot-info.outputs.email }}" | |
| - name: Notify dashboard (start) | |
| if: vars.DASHBOARD_REPO != '' | |
| env: | |
| GH_TOKEN: ${{ secrets.DASHBOARD_TOKEN }} | |
| run: | | |
| gh api repos/${{ vars.DASHBOARD_REPO }}/dispatches \ | |
| -f event_type=activity-update \ | |
| -f 'client_payload[action]=start' \ | |
| -f 'client_payload[workflow]=Evolution' || true | |
| - name: Lint evolve.sh heredocs | |
| run: python3 scripts/lint_evolve_heredocs.py | |
| - name: Run evolution session | |
| id: attempt1 | |
| continue-on-error: true | |
| env: | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| GH_TOKEN: ${{ steps.bot-token.outputs.token }} | |
| GH_PAT: ${{ secrets.GH_PAT }} | |
| FORCE_RUN: ${{ github.event_name == 'workflow_dispatch' && 'true' || '' }} | |
| FALLBACK_PROVIDER: zai | |
| FALLBACK_MODEL: glm-5 | |
| ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }} | |
| APP_ID: ${{ secrets.APP_ID }} | |
| APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} | |
| APP_INSTALLATION_ID: ${{ secrets.APP_INSTALLATION_ID }} | |
| BOT_LOGIN: ${{ steps.bot-info.outputs.login }} | |
| BOT_SLUG: ${{ steps.bot-info.outputs.slug }} | |
| X_BEARER_TOKEN: ${{ secrets.X_BEARER_TOKEN }} | |
| run: | | |
| chmod +x scripts/evolve.sh | |
| ./scripts/evolve.sh | |
| - name: Retry after 15min | |
| id: attempt2 | |
| if: steps.attempt1.outcome == 'failure' | |
| continue-on-error: true | |
| env: | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| GH_TOKEN: ${{ steps.bot-token.outputs.token }} | |
| GH_PAT: ${{ secrets.GH_PAT }} | |
| FORCE_RUN: ${{ github.event_name == 'workflow_dispatch' && 'true' || '' }} | |
| FALLBACK_PROVIDER: zai | |
| FALLBACK_MODEL: glm-5 | |
| ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }} | |
| APP_ID: ${{ secrets.APP_ID }} | |
| APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} | |
| APP_INSTALLATION_ID: ${{ secrets.APP_INSTALLATION_ID }} | |
| BOT_LOGIN: ${{ steps.bot-info.outputs.login }} | |
| BOT_SLUG: ${{ steps.bot-info.outputs.slug }} | |
| X_BEARER_TOKEN: ${{ secrets.X_BEARER_TOKEN }} | |
| run: | | |
| echo "Waiting 15 minutes before retry..." | |
| sleep 900 | |
| ./scripts/evolve.sh | |
| - name: Retry after 45min | |
| id: attempt3 | |
| if: steps.attempt1.outcome == 'failure' && steps.attempt2.outcome == 'failure' | |
| continue-on-error: true | |
| env: | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| GH_TOKEN: ${{ steps.bot-token.outputs.token }} | |
| GH_PAT: ${{ secrets.GH_PAT }} | |
| FORCE_RUN: ${{ github.event_name == 'workflow_dispatch' && 'true' || '' }} | |
| FALLBACK_PROVIDER: zai | |
| FALLBACK_MODEL: glm-5 | |
| ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }} | |
| APP_ID: ${{ secrets.APP_ID }} | |
| APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} | |
| APP_INSTALLATION_ID: ${{ secrets.APP_INSTALLATION_ID }} | |
| BOT_LOGIN: ${{ steps.bot-info.outputs.login }} | |
| BOT_SLUG: ${{ steps.bot-info.outputs.slug }} | |
| X_BEARER_TOKEN: ${{ secrets.X_BEARER_TOKEN }} | |
| run: | | |
| echo "Waiting 45 minutes before retry..." | |
| sleep 2700 | |
| ./scripts/evolve.sh | |
| - name: Check for clippy warnings | |
| if: always() | |
| run: cargo clippy --quiet --all-targets 2>&1 || true | |
| - name: Notify dashboard (end) | |
| if: always() && vars.DASHBOARD_REPO != '' | |
| env: | |
| GH_TOKEN: ${{ secrets.DASHBOARD_TOKEN }} | |
| run: | | |
| gh api repos/${{ vars.DASHBOARD_REPO }}/dispatches \ | |
| -f event_type=activity-update \ | |
| -f 'client_payload[action]=end' \ | |
| -f 'client_payload[workflow]=Evolution' \ | |
| -f 'client_payload[conclusion]=${{ job.status }}' || true | |
| gh api repos/${{ vars.DASHBOARD_REPO }}/dispatches \ | |
| -f event_type=dashboard-update || true |