@gurupanguji

Self-Hosted Social Runner Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Move the social publishing workflow onto a self-hosted macOS runner and document how to keep that runner alive.

Architecture: Keep the existing publishing script and workflow logic. Only change orchestration: restore the schedule, point the job at a self-hosted macOS runner, and add a small operational doc plus README pointer so the setup is discoverable later.

Tech Stack: GitHub Actions, YAML, Markdown, existing Python publisher script.


Task 1: Restore the workflow trigger and runner target

Files:

on:
  schedule:
    # 13:30 UTC is ~ 6:30 AM PDT / 5:30 AM PST
    - cron: '30 13 * * *'
  workflow_dispatch:
    inputs:
      date:
        description: 'Date of the snippet to publish (YYYY-MM-DD)'
        required: false
        default: ''
      platform:
        description: 'Specific platform to post to (Mastodon, Bluesky, Tumblr, LinkedIn, Threads, Instagram, X, Nostr). Leave blank for all.'
        required: false
        default: ''
jobs:
  publish:
    runs-on: [self-hosted, macOS]
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.x'
      - name: Publish Snippets
        env:
          SOCIAL_VERIFY_ATTEMPTS: 12
          SOCIAL_VERIFY_INTERVAL_SECONDS: 300
          SOCIAL_VERIFY_TIMEOUT_SECONDS: 15
          MASTODON_ACCESS_TOKEN: $
          MASTODON_API_BASE_URL: $
          BLUESKY_HANDLE: $
          BLUESKY_PASSWORD: $
          TUMBLR_CONSUMER_KEY: $
          TUMBLR_CONSUMER_SECRET: $
          TUMBLR_OAUTH_TOKEN: $
          TUMBLR_OAUTH_SECRET: $
          TUMBLR_BLOG_NAME: $
          LINKEDIN_ACCESS_TOKEN: $
          LINKEDIN_PERSON_URN: $
          THREADS_ACCESS_TOKEN: $
          THREADS_USER_ID: $
          INSTAGRAM_ACCESS_TOKEN: $
          INSTAGRAM_ACCOUNT_ID: $
          PIXELFED_ACCESS_TOKEN: $
          PIXELFED_API_BASE_URL: $
          X_CONSUMER_KEY: $
          X_CONSUMER_SECRET: $
          X_ACCESS_TOKEN: $
          X_ACCESS_TOKEN_SECRET: $
          NOSTR_PRIVATE_KEY: $
        run: |
          python -u scripts/publish_social.py \
            $TARGET_DATE \
            --verify-attempts "$SOCIAL_VERIFY_ATTEMPTS" \
            --verify-interval-seconds "$SOCIAL_VERIFY_INTERVAL_SECONDS" \
            --verify-timeout-seconds "$SOCIAL_VERIFY_TIMEOUT_SECONDS" \
            $TARGET_PLATFORM

Task 2: Add runner setup notes

Files:

# Self-Hosted Social Runner

Use a self-hosted macOS runner for `publish_social.yml` so the workflow stops spending GitHub-hosted minutes on the social publishing job.

## Requirements

- A Mac that can stay online during the daily publish window.
- The GitHub Actions runner package installed and registered with this repository.
- Python and `pip` available on the runner.
- GitHub Environment secrets already configured for the workflow.

## Runner labels

Register the runner with the default `self-hosted` and `macOS` labels.

## Maintenance

- Keep the runner online before the scheduled run.
- Update the runner package when GitHub asks for it.
- Restart the runner after OS updates.
- Remove and re-register the runner if the registration token expires or the machine changes.

Task 3: Point the README at the new runner doc

Files:

- **Self-Hosted Publish Runner**: The social publishing workflow runs on a self-hosted macOS GitHub Actions runner so it can use the existing GitHub Environment secrets without burning hosted minutes. See [docs/self-hosted-social-runner.md](./docs/self-hosted-social-runner.md).
- **Social Media Automation**: Event-driven queue system that automatically publishes to Mastodon, Bluesky, Tumblr, LinkedIn, Threads, Instagram, X (Twitter), and Nostr upon site deployment via a custom Python engine and GitHub Actions.

Task 4: Verify the workflow and docs

Files:

python - <<'PY'
from pathlib import Path
import yaml

path = Path('.github/workflows/publish_social.yml')
yaml.safe_load(path.read_text())
print('workflow yaml ok')
PY
rg -n "Self-Hosted Publish Runner|self-hosted macOS runner" README.md docs/self-hosted-social-runner.md .github/workflows/publish_social.yml
git diff -- .github/workflows/publish_social.yml README.md docs/self-hosted-social-runner.md
git add .github/workflows/publish_social.yml README.md docs/self-hosted-social-runner.md docs/superpowers/specs/2026-04-20-self-hosted-social-runner-design.md docs/superpowers/plans/2026-04-20-self-hosted-social-runner-implementation-plan.md
git commit -m "feat: move social publishing to a self-hosted runner"