How GitHub Actions Automate README Updates When Model Data Changes in free-llm-api-resources

The repository uses two GitHub Actions workflows—Update README and README Change Validator—to automatically regenerate the public README.md from a template whenever model data changes, while blocking direct manual edits to ensure data integrity.

The cheahjs/free-llm-api-resources repository maintains a curated list of free large language model (LLM) APIs that changes frequently as providers update their offerings. To keep the documentation current without manual intervention, the project employs a fully automated pipeline that fetches live model data, renders a new README from a template, and validates that all changes originate from the automation scripts.

The Automation Pipeline Overview

The system relies on a pair of coordinated workflows located in .github/workflows/. The Update README workflow handles data collection and file generation, while the README Change Validator enforces governance by preventing direct modifications to README.md. Together, they ensure the public documentation always reflects the latest free-tier model availability from providers like Groq, OpenRouter, and Cloudflare.

The Update README Workflow

Located at .github/workflows/update-readme.yml, this workflow orchestrates the data gathering and regeneration process. It runs on a scheduled cron job and can be triggered manually via workflow_dispatch.

Scheduling and Permissions

The workflow triggers automatically at midnight UTC (cron: "0 0 * * *") or on-demand. It requires specific permissions to write contents, create pull requests, and authenticate with external identity providers:

permissions:
  contents: write
  pull-requests: write
  id-token: write

Google Cloud Authentication for Gemini Quotas

To fetch accurate quota data for Google's Gemini models, the workflow authenticates using Workload Identity Federation via google-github-actions/auth@v3. This exchanges the GitHub OIDC token for a short-lived service-account JSON file without storing long-lived secrets:

- id: auth
  uses: google-github-actions/auth@v3
  with:
    workload_identity_provider: "projects/576328904266/locations/global/workloadIdentityPools/github/providers/cheahjs-org"
    project_id: ${{ secrets.GCP_PROJECT }}

Data Collection and Script Execution

After installing Python 3.12 and dependencies from src/requirements.txt, the workflow executes src/pull_available_models.py. This script contains multiple fetch_*_models functions that query each provider's public API to retrieve model names, IDs, and rate limits. The script constructs two markdown strings: model_list_markdown for free providers and trial_list_markdown for trial-credit providers.

The script then reads src/README_template.md, replaces placeholder tags with the generated content, and writes the result to the repository root:

with open(os.path.join(script_dir, "README_template.md")) as f:
    readme = f.read()
initial_templated = (
    (warning + readme)
    .replace("{{MODEL_LIST}}", model_list_markdown)
    .replace("{{TRIAL_LIST_MARKDOWN}}", trial_list_markdown)
)
toc_markdown = generate_toc(initial_templated)
with open(os.path.join(script_dir, "..", "README.md"), "w") as f:
    f.write(initial_templated.replace("{{TOC}}", toc_markdown))

Pull Request Creation and Cleanup

After removing the temporary Google credentials file (rm ${{ steps.auth.outputs.credentials_file_path }}), the workflow uses peter-evans/create-pull-request@v8 to open a PR titled "Update README with latest models" on the update-readme branch, containing only the regenerated README.md.

The README Change Validator Workflow

Located at .github/workflows/readme-change-validator.yml, this workflow prevents contributors from manually editing README.md, ensuring all changes flow through the automation pipeline. It triggers on pull requests that modify README.md, src/README_template.md, or src/pull_available_models.py.

Enforcing Script-Driven Updates

The validator performs a git diff between the PR base and head to count changes to each relevant file. If README.md changes without corresponding changes to the template or Python script, the workflow fails with exit code 1 and posts an error comment:

- name: Validate README changes
  run: |
    if [ "${{ steps.changed-files.outputs.readme_changed }}" -gt 0 ] && \
       [ "${{ steps.changed-files.outputs.template_changed }}" -eq 0 ] && \
       [ "${{ steps.changed-files.outputs.script_changed }}" -eq 0 ]; then
      echo "Error: README.md was modified without corresponding changes in src/README_template.md or src/pull_available_models.py"
      exit 1
    fi

This enforcement guarantees that any updates to the public-facing documentation originate from src/pull_available_models.py and src/README_template.md, maintaining a single source of truth for the model data.

Template and Script Architecture

The automation relies on two key files in the src/ directory that separate data collection from presentation.

The README Template Structure

src/README_template.md contains static content and placeholder tokens that the script replaces at runtime:

  • {{MODEL_LIST}} — Injections the generated markdown for free providers
  • {{TRIAL_LIST_MARKDOWN}} — Injects the generated markdown for trial-credit providers
  • {{TOC}} — Injects the auto-generated table of contents created by generate_toc()

This templating approach allows maintainers to modify static sections of the README without touching the Python code that handles API responses.

Data Aggregation Logic

src/pull_available_models.py functions as the extraction engine. Each provider (Groq, OpenRouter, Cloudflare Workers AI, etc.) has a dedicated fetch function that returns standardized model metadata. The script aggregates these into markdown lists, handles API authentication using repository secrets like GROQ_API_KEY, and manages rate-limit documentation for each endpoint.

Summary

  • Dual-workflow architecture: The Update README workflow (update-readme.yml) generates content, while the README Change Validator (readme-change-validator.yml) enforces governance.
  • Template-driven generation: src/README_template.md uses placeholders ({{MODEL_LIST}}, {{TRIAL_LIST_MARKDOWN}}, {{TOC}}) that src/pull_available_models.py populates with live API data.
  • Secure credential handling: Google Cloud authentication uses Workload Identity Federation to access Gemini quota data without persistent secrets.
  • Immutable public README: Direct edits to README.md are blocked unless accompanied by changes to the template or generator script, ensuring data consistency.

Frequently Asked Questions

How often does the README automatically update?

The Update README workflow runs on a cron schedule of 0 0 * * *, meaning it executes automatically at midnight UTC every day. It can also be triggered manually via the GitHub Actions interface using workflow_dispatch for immediate updates when urgent provider changes occur.

What happens if someone tries to edit the README.md file directly?

The README Change Validator workflow detects direct modifications by checking if README.md appears in the pull request diff without corresponding changes to src/README_template.md or src/pull_available_models.py. If this condition is met, the workflow fails and blocks the merge, posting a comment instructing the contributor to modify the template or script instead.

Why does the workflow need Google Cloud authentication?

The script queries Google's Cloud Quotas API to retrieve current rate limits and availability for Gemini models, which requires authenticated access. The workflow uses Workload Identity Federation to securely exchange the GitHub Actions OIDC token for temporary Google Cloud credentials, avoiding the storage of long-lived service account keys in repository secrets.

Can the automation handle new LLM providers?

Yes. To add a new provider, you would extend src/pull_available_models.py by adding a new fetch_*_models function that calls the provider's API and returns the standardized model metadata format. The script will automatically include the new data in the model_list_markdown or trial_list_markdown sections during the next scheduled run.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →