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:
Weekly status check — posts sync status to an Issue (free, no LLM calls)
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¶
| Requirement | Check |
|---|---|
| Source and target repos connected via action-translation | Sync workflow active |
.translate/ metadata bootstrapped | translate status --write-state done |
ANTHROPIC_API_KEY secret set | In the repo running the workflows |
TRANSLATION_PAT secret set | A 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-cnAll 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.mdWhat 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 forwardto 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.mdUsing the report¶
When the workflow runs, you’ll see a comment on the tracking Issue with a link to the artifact. To review:
Download the artifact from the GitHub Actions run page
Unzip the report folder
Run the review command locally:
npx translate review \
/path/to/backward-report/lecture-python-intro/backward-2026-03-16 \
--repo QuantEcon/lecture-python-introThis 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.jaOr 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.languageCombining 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-cnThis creates one PR per outdated file in the target repo. Use with caution — review the PRs before merging to ensure quality.
Tuning the schedule¶
| Frequency | Use case | Cost |
|---|---|---|
Weekly status | Active projects with frequent changes | Free |
Monthly backward | Standard maintenance cadence | ~$1.10/run |
On-demand (workflow_dispatch) | Before releases or intensive work periods | Variable |
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¶
Tutorial: Backward Analysis & Review — detailed walkthrough of the backward → review → Issues workflow
Tutorial: Resync a Drifted Target — manual resync workflow
CLI Reference — full command documentation