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.
Files:
Modify: .github/workflows/publish_social.yml
Step 1: Replace the paused trigger block with the scheduled one
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
Files:
Add: docs/self-hosted-social-runner.md
Step 1: Write the runner registration and maintenance note
# 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.
Files:
Modify: README.md
Step 1: Add a short note under Social Media Automation
- **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.
Files:
.github/workflows/publish_social.ymldocs/self-hosted-social-runner.mdModify: README.md
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"