Skip to content

GitHub Actions Automation for Sora 2 Prompt Management

This article is a follow-up to the implementation guide

Base article: Sora 2 Prompt Version Control Implementation

Goals

  • Automate Notion DB registration on Gist commits via GitHub Actions, eliminating manual operations
  • Auto-insert prompt diffs as PR comments to reduce review time by 30%
  • Ensure production reliability with secrets management and error retry logic

Architecture Overview

[GitHub Gist Push]
      ↓ (webhook trigger)
[GitHub Actions Workflow]
      ├→ (1) Fetch Gist diff (gh CLI)
      ├→ (2) Register to Notion API (Python script)
      └→ (3) PR diff comment (GitHub API)

[Pull Request]
      ↓ (opened/synchronize)
[Workflow: PR Comment]
      ├→ Extract prompt diff
      └→ Auto-comment credit prediction table

Implementation Steps

Step 1: Secrets Configuration and Repository Setup

Register the following secrets in your GitHub repository.

# Register in GitHub Settings → Secrets → Actions
NOTION_TOKEN=secret_xxx
NOTION_DATABASE_ID=abc123
GIST_TOKEN=ghp_xxx  # PAT with Gist read permission

Repository structure example:

.github/
  workflows/
    sync-notion.yml
    pr-review.yml
scripts/
  sync_gist_to_notion.py
  extract_prompt_diff.py

Step 2: Gist→Notion Auto-Sync Workflow

Implement workflow to auto-register Gist commits to Notion DB.

name: Sync Gist to Notion

on:
  workflow_dispatch:
    inputs:
      gist_id:
        description: 'Gist ID to sync'
        required: true

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: pip install requests tenacity

      - name: Sync to Notion
        env:
          NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
          DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
          GIST_TOKEN: ${{ secrets.GIST_TOKEN }}
          GIST_ID: ${{ github.event.inputs.gist_id }}
        run: python scripts/sync_gist_to_notion.py

Python Script (scripts/sync_gist_to_notion.py):

import os
import json
import requests
from tenacity import retry, stop_after_attempt, wait_exponential

NOTION_TOKEN = os.environ["NOTION_TOKEN"]
DATABASE_ID = os.environ["DATABASE_ID"]
GIST_ID = os.environ["GIST_ID"]
GIST_TOKEN = os.environ["GIST_TOKEN"]

@retry(stop=stop_after_attempt(3), wait=wait_exponential(min=2, max=10))
def add_to_notion(payload):
    url = "https://api.notion.com/v1/pages"
    headers = {
        "Authorization": f"Bearer {NOTION_TOKEN}",
        "Content-Type": "application/json",
        "Notion-Version": "2022-06-28"
    }
    response = requests.post(url, headers=headers, json=payload)
    response.raise_for_status()
    return response.json()

def fetch_gist():
    url = f"https://api.github.com/gists/{GIST_ID}"
    headers = {"Authorization": f"token {GIST_TOKEN}"}
    response = requests.get(url, headers=headers)
    response.raise_for_status()
    return response.json()

def main():
    gist = fetch_gist()
    for filename, file_data in gist["files"].items():
        if filename.endswith(".json"):
            prompt_data = json.loads(file_data["content"])
            payload = {
                "parent": {"database_id": DATABASE_ID},
                "properties": {
                    "Name": {"title": [{"text": {"content": prompt_data["id"]}}]},
                    "Prompt": {"rich_text": [{"text": {"content": prompt_data["prompt"][:2000]}}]},
                    "Credits": {"number": prompt_data["metadata"]["credits_used"]},
                    "Success": {"checkbox": prompt_data["metadata"]["success"]},
                    "Tags": {"multi_select": [{"name": t} for t in prompt_data["metadata"]["tags"]]}
                }
            }
            add_to_notion(payload)
            print(f"✅ Synced: {filename}")

if __name__ == "__main__":
    main()

Step 3: Auto PR Diff Comment Insertion

Extract prompt diffs on PR creation and comment with credit prediction.

name: PR Prompt Review

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Extract prompt diff
        id: diff
        run: |
          git diff origin/main...HEAD -- '*.json' > diff.txt
          python scripts/extract_prompt_diff.py diff.txt > comment.md

      - name: Post PR comment
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const body = fs.readFileSync('comment.md', 'utf8');
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: body
            });

Diff Extraction Script (scripts/extract_prompt_diff.py):

import sys
import json
import re

def parse_diff(diff_file):
    with open(diff_file) as f:
        content = f.read()

    changes = []
    for match in re.finditer(r'-"prompt": "(.*?)"\n\+"prompt": "(.*?)"', content, re.DOTALL):
        old, new = match.groups()
        changes.append({"old": old[:100], "new": new[:100]})

    if not changes:
        return "No differences"

    table = "| Before | After | Est. Impact |\n|--------|-------|-------------|\n"
    for i, ch in enumerate(changes, 1):
        credit_impact = "+10" if len(ch["new"]) > len(ch["old"]) else "-5"
        table += f"| {ch['old'][:50]}... | {ch['new'][:50]}... | {credit_impact}cr |\n"

    return f"## Prompt Diff Review\n\n{table}\n\nEst. Total Impact: {sum([10 if len(c['new'])>len(c['old']) else -5 for c in changes])}cr"

if __name__ == "__main__":
    print(parse_diff(sys.argv[1]))

Benchmark: Before/After Automation

MetricManualAutomatedImprovement
Notion Registration Time5min/item30sec/item90% reduction
Review Prep Time15min/PR0min (auto)100% elimination
Sync Error Rate12%0.5%96% reduction
Monthly Effort Saved-8 hours-

Test conditions: 3-person team, 50 prompt updates/month, 2-month operational data

Failure Patterns and Mitigations

SymptomCauseMitigation
Frequent Notion API 429 errorsRate limit exceededImplement retry + backoff with tenacity
Gist fetch auth errorsInsufficient PAT permissionsReissue token with gist scope
Empty PR diff comment failureNon-JSON file changes detectedAdd -- '*.json' filter to git diff
Unexpected workflow failuresMisconfigured SecretsPre-test with workflow_dispatch

Automation & Extension Ideas

  • Slack Integration: Notify diff summary to Slack on workflow completion
  • ML-based Credit Prediction: Train ML model on historical data for improved accuracy
  • Periodic Backups: Weekly JSON export of Notion DB to S3
  • Multi-repo Support: Monitor Gists across entire organization
  • Approval Flow: Require manual approval for high-cost prompts before Notion registration

Next Steps