Agent / Project Manager #18
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: Agent / Project Manager | |
| on: | |
| schedule: | |
| - cron: "17 */6 * * *" # Every 6 hours at minute 17 UTC | |
| workflow_dispatch: | |
| inputs: | |
| enabled: | |
| description: "Set true to run project management. Defaults off." | |
| required: false | |
| default: "false" | |
| dry_run: | |
| description: "Set false to allow label writes." | |
| required: false | |
| default: "true" | |
| apply_labels: | |
| description: "Set false to skip managed priority/effort label application." | |
| required: false | |
| default: "true" | |
| post_summary: | |
| description: "Set true to comment on today's Daily Summary discussion if it exists." | |
| required: false | |
| default: "false" | |
| discussion_category: | |
| description: "Discussion category where Daily Summary discussions are posted." | |
| required: false | |
| default: "General" | |
| limit: | |
| description: "Maximum open issues and PRs for the agent to inspect per kind." | |
| required: false | |
| default: "100" | |
| permissions: | |
| contents: read | |
| discussions: write | |
| issues: write | |
| pull-requests: write | |
| id-token: write # required for GitHub Actions OIDC broker exchange | |
| concurrency: | |
| group: agent-project-manager-${{ github.repository }} | |
| cancel-in-progress: false | |
| jobs: | |
| gate: | |
| if: ${{ vars.AGENT_ENABLED != 'false' && ((github.event_name == 'workflow_dispatch' && inputs.enabled == 'true') || (github.event_name != 'workflow_dispatch' && vars.AGENT_PROJECT_MANAGEMENT_ENABLED == 'true')) }} | |
| runs-on: ${{ fromJson(vars.AGENT_RUNS_ON || '["ubuntu-latest"]') }} | |
| outputs: | |
| skip: ${{ steps.gate.outputs.skip }} | |
| mode: ${{ steps.gate.outputs.mode }} | |
| reason: ${{ steps.gate.outputs.reason }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| persist-credentials: false | |
| ref: ${{ github.event.repository.default_branch }} | |
| token: ${{ github.token }} | |
| - name: Resolve scheduled activity gate | |
| id: gate | |
| uses: ./.github/actions/scheduled-activity-gate | |
| with: | |
| github_token: ${{ github.token }} | |
| schedule_policy: ${{ vars.AGENT_SCHEDULE_POLICY || '' }} | |
| workflow: agent-project-manager.yml | |
| project-management: | |
| needs: gate | |
| if: vars.AGENT_ENABLED != 'false' && needs.gate.outputs.skip != 'true' | |
| runs-on: ${{ fromJson(vars.AGENT_RUNS_ON || '["ubuntu-latest"]') }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| persist-credentials: false | |
| ref: ${{ github.event.repository.default_branch }} | |
| token: ${{ github.token }} | |
| - name: Resolve project management configuration | |
| id: project_config | |
| shell: bash | |
| env: | |
| RAW_DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || vars.AGENT_PROJECT_MANAGEMENT_DRY_RUN || 'true' }} | |
| RAW_APPLY_LABELS: ${{ github.event_name == 'workflow_dispatch' && inputs.apply_labels || vars.AGENT_PROJECT_MANAGEMENT_APPLY_LABELS || 'true' }} | |
| RAW_POST_SUMMARY: ${{ github.event_name == 'workflow_dispatch' && inputs.post_summary || vars.AGENT_PROJECT_MANAGEMENT_POST_SUMMARY || 'false' }} | |
| RAW_DISCUSSION_CATEGORY: ${{ github.event_name == 'workflow_dispatch' && inputs.discussion_category || vars.AGENT_PROJECT_MANAGEMENT_DISCUSSION_CATEGORY || 'General' }} | |
| RAW_LIMIT: ${{ github.event_name == 'workflow_dispatch' && inputs.limit || vars.AGENT_PROJECT_MANAGEMENT_LIMIT || '100' }} | |
| run: | | |
| set -euo pipefail | |
| normalize_bool() { | |
| local value="${1:-}" | |
| local default="${2:-false}" | |
| value="$(printf '%s' "$value" | tr '[:upper:]' '[:lower:]' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" | |
| if [ -z "$value" ]; then | |
| echo "$default" | |
| return | |
| fi | |
| case "$value" in | |
| 1|true|yes|on) echo true ;; | |
| *) echo false ;; | |
| esac | |
| } | |
| positive_int_or_default() { | |
| local value="${1:-}" | |
| local default="${2:-100}" | |
| if printf '%s' "$value" | grep -Eq '^[1-9][0-9]*$'; then | |
| echo "$value" | |
| else | |
| echo "$default" | |
| fi | |
| } | |
| dry_run="$(normalize_bool "$RAW_DRY_RUN" true)" | |
| apply_labels="$(normalize_bool "$RAW_APPLY_LABELS" true)" | |
| post_summary="$(normalize_bool "$RAW_POST_SUMMARY" false)" | |
| discussion_category="${RAW_DISCUSSION_CATEGORY:-General}" | |
| limit="$(positive_int_or_default "$RAW_LIMIT" 100)" | |
| { | |
| echo "dry_run=${dry_run}" | |
| echo "apply_labels=${apply_labels}" | |
| echo "post_summary=${post_summary}" | |
| echo "discussion_category=${discussion_category}" | |
| echo "limit=${limit}" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Resolve GitHub auth | |
| id: auth | |
| uses: ./.github/actions/resolve-github-auth | |
| with: | |
| app_id: ${{ secrets.AGENT_APP_ID }} | |
| app_private_key: ${{ secrets.AGENT_APP_PRIVATE_KEY }} | |
| pat: ${{ secrets.AGENT_PAT }} | |
| fallback_token: ${{ github.token }} | |
| - name: Resolve project manager provider | |
| id: provider | |
| uses: ./.github/actions/resolve-agent-provider | |
| with: | |
| route: project-manager | |
| default_provider: ${{ vars.AGENT_DEFAULT_PROVIDER || 'auto' }} | |
| openai_api_key: ${{ secrets.OPENAI_API_KEY }} | |
| claude_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| model_policy: ${{ vars.AGENT_MODEL_POLICY || '' }} | |
| - name: Setup selected provider | |
| uses: ./.github/actions/setup-agent-runtime | |
| with: | |
| install_codex: ${{ steps.provider.outputs.install_codex }} | |
| install_claude: ${{ steps.provider.outputs.install_claude }} | |
| - name: Resolve task timeout | |
| id: task_timeout | |
| env: | |
| AGENT_TASK_TIMEOUT_POLICY: ${{ vars.AGENT_TASK_TIMEOUT_POLICY || '' }} | |
| ROUTE: answer | |
| run: node .agent/dist/cli/resolve-task-timeout.js | |
| - name: Run project manager agent | |
| id: project_manager | |
| timeout-minutes: ${{ fromJson(steps.task_timeout.outputs.minutes || '30') }} | |
| uses: ./.github/actions/run-agent-task | |
| with: | |
| agent: ${{ steps.provider.outputs.provider }} | |
| github_token: ${{ steps.auth.outputs.token }} | |
| secondary_github_token: ${{ secrets.AGENT_SECONDARY_GITHUB_TOKEN }} | |
| openai_api_key: ${{ secrets.OPENAI_API_KEY }} | |
| claude_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| model: ${{ steps.provider.outputs.model }} | |
| display_model: ${{ vars.AGENT_DISPLAY_MODEL || '' }} | |
| permission_mode: approve-all | |
| prompt: project-manager | |
| route: answer | |
| memory_mode_override: disabled | |
| rubrics_mode_override: disabled | |
| session_policy: none | |
| request_text: | | |
| Run the scheduled project-manager pass for ${{ github.repository }}. | |
| Configuration: | |
| - repository: ${{ github.repository }} | |
| - limit per kind: ${{ steps.project_config.outputs.limit }} | |
| - dry run: ${{ steps.project_config.outputs.dry_run }} | |
| - apply labels after agent: ${{ steps.project_config.outputs.apply_labels }} | |
| - post summary after agent: ${{ steps.project_config.outputs.post_summary }} | |
| - Daily Summary discussion category: ${{ steps.project_config.outputs.discussion_category }} | |
| - workflow schedule: every 6 hours at minute 17 UTC | |
| requested_by: ${{ github.actor }} | |
| source_kind: workflow_dispatch | |
| target_kind: repository | |
| target_number: '0' | |
| target_url: ${{ github.server_url }}/${{ github.repository }} | |
| reasoning_effort: ${{ steps.provider.outputs.reasoning_effort || 'medium' }} | |
| workflow: agent-project-manager.yml | |
| - name: Apply managed label plan | |
| id: managed_labels | |
| env: | |
| AGENT_PROJECT_MANAGEMENT_APPLY_LABELS: ${{ steps.project_config.outputs.apply_labels }} | |
| AGENT_PROJECT_MANAGEMENT_DRY_RUN: ${{ steps.project_config.outputs.dry_run }} | |
| BODY_FILE: ${{ steps.project_manager.outputs.response_file }} | |
| GH_TOKEN: ${{ steps.auth.outputs.token }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| GITHUB_TOKEN: ${{ steps.auth.outputs.token }} | |
| run: node .agent/dist/cli/apply-project-management-labels.js | |
| - name: Publish project management summary | |
| env: | |
| AGENT_PROJECT_MANAGEMENT_DISCUSSION_CATEGORY: ${{ steps.project_config.outputs.discussion_category }} | |
| AGENT_PROJECT_MANAGEMENT_POST_SUMMARY: ${{ steps.project_config.outputs.post_summary }} | |
| BODY: ${{ steps.managed_labels.outputs.summary }} | |
| GH_TOKEN: ${{ steps.auth.outputs.token }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| GITHUB_TOKEN: ${{ steps.auth.outputs.token }} | |
| run: node .agent/dist/cli/post-project-management-summary.js |