Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Tutorial: Automated Maintenance

Set up scheduled status checks and backward analysis via GitHub Actions

The CLI tools (status, backward, review) are designed for local use, but you can also run them on a schedule via GitHub Actions to catch drift and discover backport suggestions automatically.

This tutorial sets up two maintenance workflows:

  1. Weekly status check — posts sync status to an Issue (free, no LLM calls)

  2. Monthly backward analysis — runs LLM analysis and uploads the report as an artifact

Cost: Status checks are free. Monthly backward analysis is ~$1.10 for a 51-file project.

Prerequisites

RequirementCheck
Source and target repos connected via action-translationSync workflow active
.translate/ metadata bootstrappedtranslate status --write-state done
ANTHROPIC_API_KEY secret setIn the repo running the workflows
TRANSLATION_PAT secret setA GitHub PAT with access to the target repo (needed to checkout private/cross-repo targets)

Before setting up automated workflows, verify the repos are properly configured:

npx translate doctor -t ~/repos/lecture-intro.zh-cn

All checks should pass (✅). Fix any issues before configuring GitHub Actions.


Workflow 1: Weekly status check

This workflow runs translate status weekly and posts the results as a comment on a tracking Issue. No API key needed — it’s a free structural comparison.

Create a tracking Issue

In your source repository, create a GitHub Issue titled “Translation sync status” (or similar). Note the Issue number — you’ll reference it in the workflow.

Create the workflow

Create .github/workflows/translation-status.yml in the source repository:

name: Translation Status Check

on:
  schedule:
    - cron: '0 9 * * 1'  # Every Monday at 9:00 UTC
  workflow_dispatch:        # Manual trigger

permissions:
  issues: write

jobs:
  check-status:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout source
        uses: actions/checkout@v4
        with:
          fetch-depth: 0    # Full history for git metadata

      - name: Checkout target
        uses: actions/checkout@v4
        with:
          repository: QuantEcon/lecture-intro.zh-cn
          path: target
          token: ${{ secrets.TRANSLATION_PAT }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install action-translation CLI
        run: |
          git clone https://github.com/QuantEcon/action-translation.git /tmp/action-translation
          cd /tmp/action-translation
          npm ci
          npm run build:cli

      - name: Run status check
        id: status
        run: |
          cd /tmp/action-translation
          npx translate status \
            -s ${{ github.workspace }} \
            -t ${{ github.workspace }}/target \
            --json > /tmp/status.json

          # Generate summary for Issue comment
          echo "## Translation Status — $(date -u +%Y-%m-%d)" > /tmp/status-comment.md
          echo "" >> /tmp/status-comment.md
          echo '```' >> /tmp/status-comment.md
          npx translate status \
            -s ${{ github.workspace }} \
            -t ${{ github.workspace }}/target >> /tmp/status-comment.md
          echo '```' >> /tmp/status-comment.md
          echo "" >> /tmp/status-comment.md

          # Count statuses from JSON
          ALIGNED=$(jq '[.entries[] | select(.status == "ALIGNED")] | length' /tmp/status.json)
          OUTDATED=$(jq '[.entries[] | select(.status == "OUTDATED")] | length' /tmp/status.json)
          TOTAL=$(jq '.entries | length' /tmp/status.json)
          echo "aligned=$ALIGNED" >> "$GITHUB_OUTPUT"
          echo "outdated=$OUTDATED" >> "$GITHUB_OUTPUT"
          echo "total=$TOTAL" >> "$GITHUB_OUTPUT"

          if [ "$OUTDATED" -gt 0 ]; then
            echo "" >> /tmp/status-comment.md
            echo "⚠️ **$OUTDATED of $TOTAL files are outdated.** Consider running \`translate forward\` to resync." >> /tmp/status-comment.md
          else
            echo "✅ **All $TOTAL files are aligned.**" >> /tmp/status-comment.md
          fi

      - name: Post to tracking Issue
        uses: peter-evans/create-or-update-comment@v4
        with:
          issue-number: 1    # ← Replace with your tracking Issue number
          body-path: /tmp/status-comment.md

What you get

Every Monday, the tracking Issue receives a comment like:

Translation Status — 2026-03-16

Sync Status: lecture-python-intro ↔ lecture-intro.zh-cn (zh-cn)

  File                              Status
  ────────────────────────────────  ────────────────────
  cobweb.md                         ✅ ALIGNED
  solow.md                          ✅ ALIGNED
  cagan_adaptive.md                 ⏳ OUTDATED

1 of 3 files are outdated. Consider running translate forward to resync.


Workflow 2: Monthly backward analysis

This workflow runs translate backward monthly and uploads the report as a workflow artifact. A maintainer can download the report and run translate review locally to create Issues.

Create .github/workflows/translation-backward.yml in the source repository:

name: Monthly Backward Analysis

on:
  schedule:
    - cron: '0 9 1 * *'  # 1st of every month at 9:00 UTC
  workflow_dispatch:        # Manual trigger

permissions:
  issues: write

jobs:
  backward-analysis:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout source
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Checkout target
        uses: actions/checkout@v4
        with:
          repository: QuantEcon/lecture-intro.zh-cn
          path: target
          token: ${{ secrets.TRANSLATION_PAT }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install action-translation CLI
        run: |
          git clone https://github.com/QuantEcon/action-translation.git /tmp/action-translation
          cd /tmp/action-translation
          npm ci
          npm run build:cli

      - name: Run backward analysis
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          cd /tmp/action-translation
          npx translate backward \
            -s ${{ github.workspace }} \
            -t ${{ github.workspace }}/target \
            -o /tmp/backward-report \
            --json

      - name: Upload report as artifact
        uses: actions/upload-artifact@v4
        with:
          name: backward-report-${{ github.run_id }}
          path: /tmp/backward-report/
          retention-days: 90

      - name: Post summary to tracking Issue
        run: |
          SUMMARY_DIR=$(ls -d /tmp/backward-report/*/backward-* 2>/dev/null | head -1)
          if [ -n "$SUMMARY_DIR" ] && [ -f "$SUMMARY_DIR/_summary.md" ]; then
            SUGGESTIONS=$(grep -c "SUGGESTION" "$SUMMARY_DIR/_summary.md" || echo "0")
            echo "## Backward Analysis — $(date -u +%Y-%m-%d)" > /tmp/backward-comment.md
            echo "" >> /tmp/backward-comment.md
            echo "Backward analysis completed. Found suggestions in the translation worth reviewing." >> /tmp/backward-comment.md
            echo "" >> /tmp/backward-comment.md
            echo "📥 **Download the report** from [workflow artifacts](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) and review locally:" >> /tmp/backward-comment.md
            echo "" >> /tmp/backward-comment.md
            echo '```bash' >> /tmp/backward-comment.md
            echo "npx translate review /path/to/downloaded/report --repo ${{ github.repository }}" >> /tmp/backward-comment.md
            echo '```' >> /tmp/backward-comment.md
          else
            echo "## Backward Analysis — $(date -u +%Y-%m-%d)" > /tmp/backward-comment.md
            echo "" >> /tmp/backward-comment.md
            echo "✅ No actionable suggestions found. Translations are in sync with source." >> /tmp/backward-comment.md
          fi

      - name: Comment on Issue
        uses: peter-evans/create-or-update-comment@v4
        with:
          issue-number: 1    # ← Replace with your tracking Issue number
          body-path: /tmp/backward-comment.md

Using the report

When the workflow runs, you’ll see a comment on the tracking Issue with a link to the artifact. To review:

  1. Download the artifact from the GitHub Actions run page

  2. Unzip the report folder

  3. Run the review command locally:

npx translate review \
  /path/to/backward-report/lecture-python-intro/backward-2026-03-16 \
  --repo QuantEcon/lecture-python-intro

This walks through suggestions interactively and creates Issues for the ones you accept.


Multi-language maintenance

For projects with multiple target languages, you can run checks for each language in parallel:

jobs:
  check-chinese:
    runs-on: ubuntu-latest
    steps:
      # ... same pattern with lecture-intro.zh-cn

  check-japanese:
    runs-on: ubuntu-latest
    steps:
      # ... same pattern with lecture-python-intro.ja

Or use a matrix strategy:

jobs:
  check-status:
    strategy:
      matrix:
        include:
          - target-repo: QuantEcon/lecture-intro.zh-cn       # Real repo name (predates setup convention)
            language: zh-cn
          - target-repo: QuantEcon/lecture-python-intro.ja  # setup-derived name
            language: ja
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/checkout@v4
        with:
          repository: ${{ matrix.target-repo }}
          path: target
          token: ${{ secrets.TRANSLATION_PAT }}
      # ... rest of pipeline using matrix.language

Combining with forward resync

When the status check finds OUTDATED files, you have two options:

Option A: Wait for natural sync

If the source repo is actively receiving PRs, the sync action handles changes naturally when PRs merge. OUTDATED files resync automatically when the relevant sections are changed.

Option B: Automated forward resync

For proactive resync, add a step to the status workflow that triggers forward when drift is detected:

      - name: Resync outdated files
        if: steps.status.outputs.outdated > 0
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          cd /tmp/action-translation
          npx translate forward \
            -s ${{ github.workspace }} \
            -t ${{ github.workspace }}/target \
            --github QuantEcon/lecture-intro.zh-cn

This creates one PR per outdated file in the target repo. Use with caution — review the PRs before merging to ensure quality.


Tuning the schedule

FrequencyUse caseCost
Weekly statusActive projects with frequent changesFree
Monthly backwardStandard maintenance cadence~$1.10/run
On-demand (workflow_dispatch)Before releases or intensive work periodsVariable

Adjust the cron expressions to match your project’s pace:

# Every Monday at 9am UTC
- cron: '0 9 * * 1'

# 1st and 15th of each month
- cron: '0 9 1,15 * *'

# Daily (for very active projects)
- cron: '0 9 * * *'

Troubleshooting

Workflow doesn’t trigger on schedule

GitHub Actions may skip scheduled runs if the repository is inactive for 60+ days. Push a commit or manually trigger the workflow to reactivate.

Clone fails for private target repo

Ensure TRANSLATION_PAT has repo scope and access to the target repository.

Backward analysis times out

The default GitHub Actions timeout is 6 hours, which is more than enough. If you have a very large project, consider adding --exclude patterns for non-essential files.

Next steps