holon 0.14.1

A headless, event-driven runtime for long-lived agents
Documentation
name: Holon Solve
description: Run the Rust Holon GitHub solve preset against a checked-out repository.
branding:
  icon: cpu
  color: blue

inputs:
  ref:
    description: GitHub issue or PR reference, such as owner/repo#123.
    required: true
  repo:
    description: Repository hint for numeric refs.
    required: false
    default: ''
  base:
    description: Base branch hint.
    required: false
    default: ''
  goal:
    description: Explicit solve goal.
    required: false
    default: ''
  role:
    description: Optional role hint.
    required: false
    default: ''
  model:
    description: Holon model ref, such as openai/gpt-5.4 or anthropic/claude-sonnet-4-6.
    required: false
    default: ''
  max_turns:
    description: Maximum foreground model turns.
    required: false
    default: '12'
  anthropic_auth_token:
    description: Anthropic Auth Token.
    required: false
  anthropic_api_key:
    description: Legacy alias for anthropic_auth_token.
    required: false
    deprecationMessage: Use anthropic_auth_token instead.
  anthropic_base_url:
    description: Anthropic Base URL.
    required: false
    default: https://api.anthropic.com
  openai_api_key:
    description: OpenAI API key.
    required: false
  openai_base_url:
    description: OpenAI Base URL.
    required: false
    default: ''
  github_token:
    description: Explicit GitHub token override. Defaults to Holonbot broker token when available, then github.token.
    required: false
    default: ''
  holonbot_broker_url:
    description: Holonbot token broker URL. Leave empty to skip OIDC broker exchange.
    required: false
    default: https://bot.holon.run/api/exchange-token
  holonbot_oidc_audience:
    description: OIDC audience for Holonbot token broker exchange.
    required: false
    default: holon-token-broker
  version:
    description: Holon release version to download when build_from_source is false.
    required: false
    default: latest
  build_from_source:
    description: Build Holon from source before running.
    required: false
    default: 'true'
  holon_repository:
    description: Holon repository for source builds.
    required: false
    default: holon-run/holon
  holon_ref:
    description: Optional Holon git ref for source builds.
    required: false
    default: ''
  workspace:
    description: Checked-out repository path. Defaults to GITHUB_WORKSPACE.
    required: false
    default: ''
  cwd:
    description: Working directory for the solve run. Defaults to workspace.
    required: false
    default: ''
  input_dir:
    description: Input context directory.
    required: false
    default: ''
  output_dir:
    description: Output artifact directory.
    required: false
    default: ''
  state_dir:
    description: Holon home directory for runtime state.
    required: false
    default: ''

runs:
  using: composite
  steps:
    - name: Checkout Holon source
      if: inputs.build_from_source == 'true'
      shell: bash
      env:
        HOLON_REPOSITORY: ${{ inputs.holon_repository }}
        HOLON_REF: ${{ inputs.holon_ref }}
      run: |
        set -euo pipefail
        src_dir="$RUNNER_TEMP/holon-source"
        rm -rf "$src_dir"
        git clone --depth 1 "https://github.com/${HOLON_REPOSITORY}.git" "$src_dir"
        if [ -n "$HOLON_REF" ]; then
          git -C "$src_dir" fetch --depth 1 origin "$HOLON_REF"
          git -C "$src_dir" checkout FETCH_HEAD
        fi
        echo "HOLON_SOURCE_DIR=$src_dir" >> "$GITHUB_ENV"

    - name: Set up Rust
      if: inputs.build_from_source == 'true'
      uses: dtolnay/rust-toolchain@stable

    - name: Build Holon from source
      if: inputs.build_from_source == 'true'
      shell: bash
      run: |
        set -euo pipefail
        cargo build --release --locked --manifest-path "$HOLON_SOURCE_DIR/Cargo.toml"
        mkdir -p "$RUNNER_TEMP/holon/bin"
        cp "$HOLON_SOURCE_DIR/target/release/holon" "$RUNNER_TEMP/holon/bin/holon"
        chmod +x "$RUNNER_TEMP/holon/bin/holon"

    - name: Download Holon binary
      if: inputs.build_from_source != 'true'
      shell: bash
      env:
        INPUT_VERSION: ${{ inputs.version }}
      run: |
        set -euo pipefail
        platform="$(uname -s | tr '[:upper:]' '[:lower:]')"
        arch="$(uname -m)"
        case "$arch" in
          x86_64) arch=amd64 ;;
          arm64|aarch64) arch=arm64 ;;
        esac
        if [ "$platform" != "linux" ] && [ "$platform" != "darwin" ]; then
          echo "::error::Unsupported platform: $platform"
          exit 1
        fi
        if [ "$platform" = "linux" ] && [ "$arch" != "amd64" ]; then
          echo "::error::Linux release assets currently support amd64 only."
          exit 1
        fi
        release_path=latest/download
        if [ "$INPUT_VERSION" != "latest" ]; then
          release_path="download/$INPUT_VERSION"
        fi
        mkdir -p "$RUNNER_TEMP/holon/bin"
        curl -fsSL "https://github.com/holon-run/holon/releases/$release_path/holon-$platform-$arch.tar.gz" |
          tar -xz -C "$RUNNER_TEMP/holon/bin"
        if [ -f "$RUNNER_TEMP/holon/bin/holon" ]; then
          chmod +x "$RUNNER_TEMP/holon/bin/holon"
        elif [ -f "$RUNNER_TEMP/holon/bin/holon-$platform-$arch" ]; then
          mv "$RUNNER_TEMP/holon/bin/holon-$platform-$arch" "$RUNNER_TEMP/holon/bin/holon"
          chmod +x "$RUNNER_TEMP/holon/bin/holon"
        else
          echo "::error::Failed to find holon binary after extracting release asset."
          ls -la "$RUNNER_TEMP/holon/bin"
          exit 1
        fi

    - name: Resolve GitHub token
      id: github-token
      shell: bash
      env:
        INPUT_GITHUB_TOKEN: ${{ inputs.github_token }}
        HOLONBOT_BROKER_URL: ${{ inputs.holonbot_broker_url }}
        HOLONBOT_OIDC_AUDIENCE: ${{ inputs.holonbot_oidc_audience }}
        GITHUB_TOKEN_FALLBACK: ${{ github.token }}
      run: |
        set -euo pipefail

        if [ -n "$INPUT_GITHUB_TOKEN" ]; then
          echo "Using explicit github_token input."
          echo "::add-mask::$INPUT_GITHUB_TOKEN"
          {
            echo "token=$INPUT_GITHUB_TOKEN"
            echo "actor_source=explicit"
          } >> "$GITHUB_OUTPUT"
          exit 0
        fi

        if [ -n "${ACTIONS_ID_TOKEN_REQUEST_TOKEN:-}" ] && [ -n "${ACTIONS_ID_TOKEN_REQUEST_URL:-}" ] && [ -n "$HOLONBOT_BROKER_URL" ]; then
          echo "Fetching GitHub Actions OIDC token for Holonbot broker exchange."
          oidc_url="$ACTIONS_ID_TOKEN_REQUEST_URL"
          if [ -n "$HOLONBOT_OIDC_AUDIENCE" ]; then
            if [[ "$oidc_url" == *\?* ]]; then
              oidc_url="${oidc_url}&audience=${HOLONBOT_OIDC_AUDIENCE}"
            else
              oidc_url="${oidc_url}?audience=${HOLONBOT_OIDC_AUDIENCE}"
            fi
          fi

          oidc_response="$(curl -sS -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$oidc_url" || true)"
          oidc_token="$(printf '%s' "$oidc_response" | jq -r '.value // empty' 2>/dev/null || true)"
          if [ -n "$oidc_token" ] && [ "$oidc_token" != "null" ]; then
            broker_response="$(curl -sS -X POST "$HOLONBOT_BROKER_URL" \
              -H "Authorization: Bearer $oidc_token" \
              -H "Content-Type: application/json" || true)"
            bot_token="$(printf '%s' "$broker_response" | jq -r '.token // empty' 2>/dev/null || true)"
            if [ -n "$bot_token" ] && [ "$bot_token" != "null" ]; then
              echo "Successfully obtained Holonbot token from broker."
              echo "::add-mask::$bot_token"
              {
                echo "token=$bot_token"
                echo "actor_login=holonbot[bot]"
                echo "actor_type=App"
                echo "actor_app_slug=holonbot"
                echo "actor_source=token"
              } >> "$GITHUB_OUTPUT"
              exit 0
            fi
            broker_error="$(printf '%s' "$broker_response" | jq -r '.error // empty' 2>/dev/null || true)"
            broker_message="$(printf '%s' "$broker_response" | jq -r '.message // empty' 2>/dev/null || true)"
            echo "::warning title=Holonbot Auth::Token broker exchange failed: ${broker_error:-unknown error} ${broker_message:-}"
          else
            echo "::warning title=Holonbot Auth::Failed to fetch OIDC token from GitHub Actions runtime."
          fi
        else
          echo "Skipping Holonbot token exchange: id-token permission is unavailable or holonbot_broker_url is empty."
        fi

        echo "Falling back to github.token."
        echo "::add-mask::$GITHUB_TOKEN_FALLBACK"
        {
          echo "token=$GITHUB_TOKEN_FALLBACK"
          echo "actor_login=github-actions[bot]"
          echo "actor_type=App"
          echo "actor_app_slug=github-actions"
          echo "actor_source=token"
        } >> "$GITHUB_OUTPUT"

    - name: Run Holon solve
      shell: bash
      env:
        INPUT_REF: ${{ inputs.ref }}
        INPUT_REPO: ${{ inputs.repo }}
        INPUT_BASE: ${{ inputs.base }}
        INPUT_GOAL: ${{ inputs.goal }}
        INPUT_ROLE: ${{ inputs.role }}
        INPUT_MODEL: ${{ inputs.model }}
        INPUT_MAX_TURNS: ${{ inputs.max_turns }}
        INPUT_WORKSPACE: ${{ inputs.workspace }}
        INPUT_CWD: ${{ inputs.cwd }}
        INPUT_INPUT_DIR: ${{ inputs.input_dir }}
        INPUT_OUTPUT_DIR: ${{ inputs.output_dir }}
        INPUT_STATE_DIR: ${{ inputs.state_dir }}
        ANTHROPIC_AUTH_TOKEN_INPUT: ${{ inputs.anthropic_auth_token || inputs.anthropic_api_key }}
        ANTHROPIC_BASE_URL_INPUT: ${{ inputs.anthropic_base_url }}
        OPENAI_API_KEY_INPUT: ${{ inputs.openai_api_key }}
        OPENAI_BASE_URL_INPUT: ${{ inputs.openai_base_url }}
        GITHUB_TOKEN_INPUT: ${{ steps.github-token.outputs.token }}
        HOLON_ACTOR_LOGIN: ${{ steps.github-token.outputs.actor_login }}
        HOLON_ACTOR_TYPE: ${{ steps.github-token.outputs.actor_type }}
        HOLON_ACTOR_APP_SLUG: ${{ steps.github-token.outputs.actor_app_slug }}
        HOLON_ACTOR_SOURCE: ${{ steps.github-token.outputs.actor_source }}
      run: |
        set -euo pipefail
        export PATH="$RUNNER_TEMP/holon/bin:$PATH"
        export GITHUB_TOKEN="$GITHUB_TOKEN_INPUT"
        export GH_TOKEN="$GITHUB_TOKEN_INPUT"
        export HOLON_GITHUB_TOKEN="$GITHUB_TOKEN_INPUT"
        if [ -n "$ANTHROPIC_AUTH_TOKEN_INPUT" ]; then
          export ANTHROPIC_AUTH_TOKEN="$ANTHROPIC_AUTH_TOKEN_INPUT"
        fi
        if [ -n "$ANTHROPIC_BASE_URL_INPUT" ]; then
          export ANTHROPIC_BASE_URL="$ANTHROPIC_BASE_URL_INPUT"
        fi
        if [ -n "$OPENAI_API_KEY_INPUT" ]; then
          export OPENAI_API_KEY="$OPENAI_API_KEY_INPUT"
        fi
        if [ -n "$OPENAI_BASE_URL_INPUT" ]; then
          export OPENAI_BASE_URL="$OPENAI_BASE_URL_INPUT"
        fi

        workspace="$INPUT_WORKSPACE"
        if [ -z "$workspace" ]; then
          workspace="${GITHUB_WORKSPACE:-$PWD}"
        fi
        cwd="$INPUT_CWD"
        if [ -z "$cwd" ]; then
          cwd="$workspace"
        fi
        input_dir="$INPUT_INPUT_DIR"
        if [ -z "$input_dir" ]; then
          input_dir="$RUNNER_TEMP/holon/input"
        fi
        output_dir="$INPUT_OUTPUT_DIR"
        if [ -z "$output_dir" ]; then
          output_dir="$RUNNER_TEMP/holon/output"
        fi
        state_dir="$INPUT_STATE_DIR"
        if [ -z "$state_dir" ]; then
          state_dir="$RUNNER_TEMP/holon/home"
        fi
        mkdir -p "$input_dir" "$output_dir" "$state_dir"

        args=("$INPUT_REF" --home "$state_dir" --workspace "$workspace" --cwd "$cwd" --input "$input_dir" --output "$output_dir" --max-turns "$INPUT_MAX_TURNS" --json)
        if [ -n "$INPUT_REPO" ]; then
          args+=(--repo "$INPUT_REPO")
        fi
        if [ -n "$INPUT_BASE" ]; then
          args+=(--base "$INPUT_BASE")
        fi
        if [ -n "$INPUT_GOAL" ]; then
          args+=(--goal "$INPUT_GOAL")
        fi
        if [ -n "$INPUT_ROLE" ]; then
          args+=(--role "$INPUT_ROLE")
        fi
        if [ -n "$INPUT_MODEL" ]; then
          args+=(--model "$INPUT_MODEL")
        fi

        holon solve "${args[@]}"