Repository navigation
SEO Content Agent #66
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: SEO Content Agent | |
| on: | |
| schedule: | |
| - cron: '0 14 * * 1,3,5' | |
| workflow_dispatch: | |
| inputs: | |
| topic: | |
| description: Optional topic override for a manual run | |
| required: false | |
| type: string | |
| keyword: | |
| description: Optional target keyword override for a manual run | |
| required: false | |
| type: string | |
| dry_run: | |
| description: Generate artifacts without creating a Ghost draft | |
| required: true | |
| default: false | |
| type: boolean | |
| max_drafts: | |
| description: Maximum Ghost drafts to create | |
| required: true | |
| default: '1' | |
| type: choice | |
| options: | |
| - '1' | |
| content_focus: | |
| description: Optional content focus override | |
| required: true | |
| default: auto | |
| type: choice | |
| options: | |
| - auto | |
| - logistics-software | |
| - supply-chain-software | |
| - fleetbase-api-tutorial | |
| generate_feature_image: | |
| description: Generate and attach an OpenAI feature image when creating the Ghost draft | |
| required: true | |
| default: true | |
| type: boolean | |
| generate_feature_image_in_dry_run: | |
| description: Also call OpenAI Images during dry runs | |
| required: true | |
| default: false | |
| type: boolean | |
| allow_seed_fallback: | |
| description: Allow continuing without Ahrefs results | |
| required: true | |
| default: false | |
| type: boolean | |
| use_ahrefs: | |
| description: Use Ahrefs keyword research for this run | |
| required: true | |
| default: false | |
| type: boolean | |
| topic_mode: | |
| description: Topic generation mode | |
| required: true | |
| default: auto | |
| type: choice | |
| options: | |
| - auto | |
| - integration | |
| - api-tutorial | |
| - software-seo | |
| - comparison | |
| integration_target: | |
| description: Optional integration target for integration topics | |
| required: false | |
| type: string | |
| permissions: | |
| contents: read | |
| id-token: write | |
| jobs: | |
| generate: | |
| name: Generate SEO content draft | |
| runs-on: ubuntu-latest | |
| env: | |
| AHREFS_API_TOKEN: ${{ secrets.AHREFS_API_TOKEN }} | |
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | |
| OPENAI_CONTENT_MODEL: ${{ vars.OPENAI_CONTENT_MODEL || 'gpt-4.1' }} | |
| OPENAI_IMAGE_MODEL: ${{ vars.OPENAI_IMAGE_MODEL || 'gpt-image-1.5' }} | |
| GHOST_ADMIN_API_URL: ${{ vars.GHOST_ADMIN_API_URL || 'https://blog.fleetbase.io' }} | |
| GHOST_ADMIN_API_KEY: ${{ secrets.GHOST_ADMIN_API_KEY }} | |
| GHOST_API_URL: ${{ vars.GHOST_API_URL || 'https://blog.fleetbase.io' }} | |
| GHOST_CONTENT_API_KEY: ${{ secrets.GHOST_CONTENT_API_KEY }} | |
| GHOST_API_VERSION: ${{ vars.GHOST_API_VERSION || 'v6.0' }} | |
| CONTENT_AGENT_NOTIFY_WEBHOOK_URL: ${{ secrets.CONTENT_AGENT_NOTIFY_WEBHOOK_URL }} | |
| CONTENT_AGENT_TOPIC: ${{ inputs.topic || '' }} | |
| CONTENT_AGENT_KEYWORD: ${{ inputs.keyword || '' }} | |
| CONTENT_AGENT_FOCUS: ${{ inputs.content_focus || 'auto' }} | |
| CONTENT_AGENT_TOPIC_MODE: ${{ inputs.topic_mode || 'auto' }} | |
| CONTENT_AGENT_INTEGRATION_TARGET: ${{ inputs.integration_target || '' }} | |
| CONTENT_AGENT_MAX_DRAFTS: ${{ inputs.max_drafts || '1' }} | |
| CONTENT_AGENT_OUTPUT_DIR: content-agent-output | |
| CONTENT_AGENT_ALLOW_SEED_FALLBACK: ${{ inputs.allow_seed_fallback != false }} | |
| CONTENT_AGENT_USE_AHREFS: ${{ inputs.use_ahrefs == true }} | |
| CONTENT_AGENT_MAX_AHREFS_CLUSTERS: 3 | |
| CONTENT_AGENT_MAX_AHREFS_ROWS: 10 | |
| CREATE_GHOST_DRAFT: ${{ github.event_name == 'schedule' || inputs.dry_run == false }} | |
| GENERATE_FEATURE_IMAGE: ${{ inputs.generate_feature_image }} | |
| GENERATE_FEATURE_IMAGE_IN_DRY_RUN: ${{ inputs.generate_feature_image_in_dry_run }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Checkout core-api source truth | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: fleetbase/core-api | |
| path: source-truth/core-api | |
| token: ${{ secrets.FLEETBASE_SOURCE_READ_TOKEN || github.token }} | |
| - name: Checkout fleetops source truth | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: fleetbase/fleetops | |
| path: source-truth/fleetops | |
| token: ${{ secrets.FLEETBASE_SOURCE_READ_TOKEN || github.token }} | |
| - name: Checkout ledger source truth | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: fleetbase/ledger | |
| path: source-truth/ledger | |
| token: ${{ secrets.FLEETBASE_SOURCE_READ_TOKEN || github.token }} | |
| - name: Checkout storefront source truth | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: fleetbase/storefront | |
| path: source-truth/storefront | |
| token: ${{ secrets.FLEETBASE_SOURCE_READ_TOKEN || github.token }} | |
| - name: Checkout dev-engine source truth | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: fleetbase/dev-engine | |
| path: source-truth/dev-engine | |
| token: ${{ secrets.FLEETBASE_SOURCE_READ_TOKEN || github.token }} | |
| - name: Checkout iam-engine source truth | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: fleetbase/iam-engine | |
| path: source-truth/iam-engine | |
| token: ${{ secrets.FLEETBASE_SOURCE_READ_TOKEN || github.token }} | |
| - name: Checkout ember-core source truth | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: fleetbase/ember-core | |
| path: source-truth/ember-core | |
| token: ${{ secrets.FLEETBASE_SOURCE_READ_TOKEN || github.token }} | |
| - name: Checkout pallet source truth | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: fleetbase/pallet | |
| path: source-truth/pallet | |
| token: ${{ secrets.FLEETBASE_SOURCE_READ_TOKEN || github.token }} | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v3 | |
| with: | |
| version: 10 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Verify Ghost target | |
| run: | | |
| set -euo pipefail | |
| expected_url="https://blog.fleetbase.io" | |
| if [ "${GHOST_ADMIN_API_URL}" != "${expected_url}" ]; then | |
| echo "::error::GHOST_ADMIN_API_URL must target ${expected_url}." | |
| exit 1 | |
| fi | |
| if [ "${GHOST_API_URL}" != "${expected_url}" ]; then | |
| echo "::error::GHOST_API_URL must target ${expected_url}." | |
| exit 1 | |
| fi | |
| echo "Ghost target verified: ${expected_url}" | |
| - name: Run content agent self-tests | |
| run: pnpm content-agent:test | |
| - name: Prepare content research | |
| run: pnpm content-agent:prepare | |
| - name: Generate structured content artifacts | |
| run: pnpm content-agent:generate-artifacts | |
| - name: Create Ghost draft from structured artifacts | |
| run: pnpm content-agent:generate | |
| - name: Upload content agent artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: content-agent-output | |
| path: content-agent-output | |
| if-no-files-found: ignore |