Debugging Blog Automation: 7 Fixes in 24 Hours (Git Subtree Architecture)

by Alien Brain Trust AI Learning
Debugging Blog Automation: 7 Fixes in 24 Hours (Git Subtree Architecture)

Debugging Blog Automation: 7 Fixes in 24 Hours (Git Subtree Architecture)

Meta Description: Fixed blog auto-publishing in 24 hours: YAML syntax errors, Git Subtree sync, GitHub Actions permissions. Here’s what broke and how we fixed it.

Our blog auto-publishing stopped working. Posts with published: false weren’t changing to published: true on their scheduled dates. Worse, when we tried to fix it, we discovered the entire architecture was broken.

Here’s the 24-hour debugging journey that resulted in 7 fixes, a complete Git Subtree implementation, and a working automated blog workflow.

The Problem: Auto-Publish Wasn’t Running

Symptom: Blog posts dated for past dates remained unpublished.

Expected Behavior:

  • GitHub Actions workflow runs daily at 14:00 UTC
  • Finds posts with date: 2026-01-10 and published: false
  • Changes published: falsepublished: true
  • Commits changes
  • Blog deploys automatically

Reality: Workflow failed with YAML syntax error on line 152.

Fix #1: YAML Syntax Error (5 minutes)

Error:

error: You have an error in your yaml syntax on line 152

Root Cause:

# BROKEN - Variable expansion with newlines broke YAML
COMMIT_MSG="Auto-publish: Daily blog post(s) for $TODAY

Published $POST_COUNT post(s) scheduled for $(date -u +'%B %d, %Y'):
${PUBLISHED_TITLES}  # ← This variable contained newlines!

🤖 Automated by GitHub Actions"

Fix:

# FIXED - Simplified commit message
git commit -m "Auto-publish: Daily blog post(s) for $TODAY

Published $POST_COUNT post(s) scheduled for $(date -u +'%B %d, %Y')

🤖 Automated by GitHub Actions"

Lesson: Bash variable expansion with newlines inside YAML multiline strings is fragile. Keep it simple.

Commit: 57e9568

Fix #2: Build Error - Duplicate Export (10 minutes)

After fixing the YAML error, deployment failed with:

Error:

ERROR: Multiple exports with the same name "collections"
ERROR: The symbol "collections" has already been declared

Root Cause:

// config.ts had TWO exports:
export const collections = { blog };  // Line 17

// ... later ...
export const collections = {          // Line 30
  blog: blogCollection,
  course: courseCollection,
};

Fix: Removed the duplicate first export, kept the combined one.

Commit: 89aa85f

Lesson: When refactoring, grep for duplicate exports before committing.

Fix #3: The Architecture Problem (2 hours)

Now the workflow ran successfully, but posts still didn’t appear on the blog.

Discovery: The blog exists in two separate repositories:

  • alienbraintrust-private - Where we write posts
  • labs-journey-blog - Where the blog deploys from

The auto-publish workflow was running in the private repo, changing published: falsetrue there, but the deployment repo never received the changes.

Original (Broken) Flow:

Write post in private repo

Auto-publish changes published status in private repo

❌ Deployment repo has old version

❌ Blog doesn't update

Decision Point: Three options:

  1. Git Subtree (private repo = source of truth)
  2. Dual repos (manual sync)
  3. Monorepo (merge everything)

Choice: Option 1 - Git Subtree (matches original architecture intent).

Fix #4: Git Subtree Sync Workflow (1 hour)

Created: .github/workflows/sync-blog-to-deployment.yml

# Triggers after auto-publish completes
workflow_run:
  workflows: ["Auto-Publish Daily Blog Posts"]
  types: [completed]

# Uses git subtree to sync blog directory
git subtree push --prefix="03-Marketing Materials/labs-journey-blog" \
  blog-deploy main

Why Git Subtree?

  • Keeps all content in private repo (source of truth)
  • Auto-syncs to deployment repo
  • Preserves git history
  • No manual copy/paste between repos

Commit: 6dcf151

Fix #5: Permission Denied (30 minutes)

Error:

remote: Permission to base-bit/labs-journey-blog.git denied to github-actions[bot]
fatal: unable to access 'https://github.com/base-bit/labs-journey-blog.git/':
  The requested URL returned error: 403

Root Cause: The default GITHUB_TOKEN only has permissions for the current repository. Cross-repo pushes require a Personal Access Token (PAT).

Fix:

  1. Created GitHub PAT with repo scope
  2. Added as GH_PAT secret in repository settings
  3. Updated workflow to use secrets.GH_PAT instead of secrets.GITHUB_TOKEN

Commit: 5043eb1

Lesson: Cross-repository GitHub Actions need PATs, not the default token.

Fix #6: Non-Fast-Forward Push (20 minutes)

Error:

! [rejected]  main -> main (non-fast-forward)
error: failed to push some refs
hint: Updates were rejected because the tip of your current branch is behind

Root Cause: The deployment repo had diverged from the private repo (we’d made direct edits there while debugging).

Fix: Added force push fallback:

# Try normal push first
if git push blog-deploy $SPLIT_SHA:main; then
  echo "✅ Normal push successful"
else
  echo "⚠️  Trying force push..."
  git push blog-deploy $SPLIT_SHA:main --force
fi

Commit: 1da5ed1

Lesson: Initial subtree syncs often need force push. After that, everything is fast-forward.

Fix #7: Workflow Scope Permission (15 minutes)

Error:

! [remote rejected] main (refusing to allow a Personal Access Token to
  create or update workflow `.github/workflows/auto-publish.yml`
  without `workflow` scope)

Root Cause: The blog directory contained its own copy of the auto-publish workflow. GitHub requires the workflow scope to push workflow files, but we only had repo scope.

Fix: Removed the duplicate workflow from the blog directory. The auto-publish workflow should only exist in the parent repo.

Before:

alienbraintrust-private/
├── .github/workflows/auto-publish-blog.yml
└── 03-Marketing Materials/labs-journey-blog/
    └── .github/workflows/auto-publish.yml  # ← Duplicate!

After:

alienbraintrust-private/
├── .github/workflows/auto-publish-blog.yml      # ← Only here
└── 03-Marketing Materials/labs-journey-blog/
    └── .github/workflows/deploy.yml             # ← Deployment only

Commit: ec2bfbc

Lesson: Keep workflows in the appropriate repo. Don’t sync workflow files to deployment repos.

Final Architecture

Source of Truth: alienbraintrust-private

alienbraintrust-private (WRITE HERE)
├── .github/workflows/
│   ├── auto-publish-blog.yml       ← Publishes posts daily at 14:00 UTC
│   └── sync-blog-to-deployment.yml ← Syncs via git subtree
└── 03-Marketing Materials/labs-journey-blog/
    └── src/content/blog/*.md       ← Write posts here

                ↓ Git Subtree Push ↓

labs-journey-blog (DEPLOYMENT ONLY)
├── .github/workflows/
│   └── deploy.yml                  ← Deploys to GitHub Pages
└── src/content/blog/*.md           ← Auto-synced from private

                ↓ GitHub Pages ↓

https://blog.alienbraintrust.ai/

Workflow Now

Daily Auto-Publish (Scheduled):

  1. 14:00 UTC: Auto-publish workflow checks for posts dated today
  2. Changes published: falsepublished: true
  3. Commits to private repo
  4. Sync workflow triggers
  5. Git subtree pushes blog directory to deployment repo
  6. Deployment repo auto-deploys to GitHub Pages
  7. Blog updates automatically

Manual Publish (Immediate):

# Option A: Change published status
# Edit .md file: published: false → published: true
git commit -m "Publish: Post Title"
git push  # Sync workflow triggers automatically

# Option B: Trigger auto-publish manually
# Visit GitHub Actions and click "Run workflow"

Debugging Metrics

Total Time: 24 hours (intermittent work) Total Fixes: 7 Commits: 7 (each fixing one issue) Lines of Code Changed: ~500 Documentation Created: 3 guides (800+ lines)

Breakdown:

  • YAML syntax error: 5 min
  • Build error: 10 min
  • Architecture research: 2 hours
  • Git Subtree implementation: 1 hour
  • Permission issues: 30 min
  • Force push handling: 20 min
  • Workflow scope: 15 min
  • Documentation: 2 hours
  • Testing/verification: 1 hour

Key Takeaways

1. Multi-Repo Architectures Need Clear Workflows

Problem: Having the blog in two repos caused confusion about which was authoritative.

Solution: Document the architecture explicitly. Create a clear “source of truth” policy.

Files Created:

  • BLOG-WORKFLOW-ARCHITECTURE.md - Explains the two-repo setup
  • BLOG-SETUP-GUIDE.md - Step-by-step workflow
  • SETUP-GITHUB-PAT.md - Token configuration

2. Git Subtree vs Submodule

Git Subtree:

  • ✅ Simpler for contributors (just one repo to clone)
  • ✅ Can commit directly to subtree
  • ✅ No .gitmodules complexity
  • ❌ Force push needed on first sync

Git Submodule:

  • ✅ Cleaner separation
  • ✅ Each repo maintains its own history
  • ❌ More complex (nested repos)
  • ❌ Easy to forget git submodule update

Our Choice: Subtree - simpler for a blog use case.

3. GitHub Actions Cross-Repo Permissions

Default GITHUB_TOKEN:

  • ✅ Works for current repo
  • ❌ Can’t push to other repos
  • ❌ Can’t trigger workflows in other repos

Personal Access Token (PAT):

  • ✅ Works across repos
  • ✅ Can push/pull/trigger workflows
  • ⚠️ Needs proper scopes (repo, optionally workflow)
  • ⚠️ Rotate regularly (90 days recommended)

4. Debugging Multi-Step Workflows

Strategy:

  1. Identify the failure point (YAML error, build error, permission error)
  2. Fix one thing at a time (commit after each fix)
  3. Test incrementally (don’t fix 3 things and hope it works)
  4. Document as you go (future you will thank you)

Anti-pattern: Trying to fix multiple issues in one commit. When it fails, you don’t know which fix was wrong.

5. Automation Doesn’t Mean “Set and Forget”

Even automated workflows need:

  • Monitoring (check if they run successfully)
  • Error handling (what happens when the workflow fails?)
  • Recovery procedures (how to manually trigger if needed)
  • Documentation (how does this actually work?)

What’s Next

Immediate:

  • Monitor auto-publish workflow for next 7 days
  • Verify scheduled posts publish correctly
  • Document any edge cases discovered

Future Improvements:

  • Add workflow status notifications (Slack/email)
  • Implement retry logic for failed syncs
  • Add deployment preview for unpublished posts
  • Create dashboard showing upcoming scheduled posts

Long-Term:

  • Consider consolidating to monorepo (if dual-repo causes more issues)
  • Evaluate alternative deployment strategies (Netlify, Vercel)
  • Build web UI for managing scheduled posts

Files Created

Workflows:

  • .github/workflows/sync-blog-to-deployment.yml (102 lines)
  • Updated .github/workflows/auto-publish-blog.yml (simplified commit message)

Documentation:

  • BLOG-WORKFLOW-ARCHITECTURE.md (281 lines)
  • BLOG-SETUP-GUIDE.md (409 lines)
  • SETUP-GITHUB-PAT.md (145 lines)

Skills:

  • Updated .claude/skills/blog-post/SKILL.md (added workflow section)

Total Documentation: ~900 lines

Lessons for AI-Augmented Debugging

What Worked:

  • Breaking down the problem into discrete fixes
  • Committing after each fix (clear rollback points)
  • Testing each fix before moving to the next
  • Creating comprehensive documentation

What Didn’t Work:

  • Assuming the architecture was simple (it had hidden complexity)
  • Not reading the actual error messages carefully enough (saved time later)
  • Trying to fix everything at once (caused more confusion)

AI-Specific Insights:

  • Claude helped identify the Git Subtree solution quickly
  • Documentation generation was faster with AI assistance
  • But: Still needed human decision on architecture choice (Option 1 vs 2 vs 3)

Next in series: Part 2 will cover implementing monitoring and alerts for the automated workflows.

Related posts: