How `pull_available_models.py` Automatically Fetches Live Model Data and Updates the README

The pull_available_models.py script queries multiple LLM provider APIs, normalizes their model metadata into markdown lists, and injects these into a template to regenerate the repository's README.md automatically.

The free-llm-api-resources repository tracks free LLM API endpoints and their available models. The pull_available_models.py script functions as a self-contained data pipeline that fetches current model information from providers like Groq, OpenRouter, and Cloudflare, then reconstructs the project documentation without manual editing.

Loading Configuration and Initialization

The script establishes its execution context by loading environment variables via dotenv and determining its directory through the script_dir variable. This allows it to locate the template and target files using relative paths according to src/pull_available_models.py#L22-L24.

A dedicated logger is instantiated through the create_logger() function to emit debug information during execution. This logging infrastructure, implemented at src/pull_available_models.py#L26-L33, monitors each provider fetch operation for troubleshooting and verification.

Fetching Live Model Data from Provider APIs

For each supported provider, the script implements a specific fetch_*_models(logger) function (such as fetch_groq_models(), fetch_kluster_models(), and fetch_openrouter_models()). These functions issue HTTPS GET or POST requests using the requests library to query public model catalog endpoints.

The fetchers return standardized lists of dictionaries containing model metadata such as {"id": "...", "name": "...", "limits": {...}}. Each function optionally enriches the response with rate-limit data specific to that provider. The implementation pattern for Groq, which demonstrates API querying and data enrichment, appears at src/pull_available_models.py#L115-L148.

Aggregating and Normalizing Model Information

Within the main() function, the script calls every provider-specific fetch routine and concatenates their results. It sorts the aggregated models alphabetically to ensure consistent ordering, then constructs two distinct markdown sections:

  • Full model list (model_list_markdown): Contains all available models across providers
  • Trial-only list (trial_list_markdown): Filters for models available on free tiers

This aggregation logic appears in the tail section of src/pull_available_models.py, where the script prepares the content for template injection.

Template Injection and README Generation

Rather than building the README from scratch, the script uses a static template located at src/README_template.md. This template contains specific placeholders that the script replaces with generated content:

  • {{MODEL_LIST}}: Injection point for the complete model catalog
  • {{TRIAL_LIST_MARKDOWN}}: Insertion location for trial-tier models
  • {{TOC}}: Placeholder for the dynamically generated table of contents

The replacement operation occurs at src/pull_available_models.py#L53-L63, where the script loads the template, prepends an optional warning message, and substitutes the markdown lists into the document structure.

Table of Contents Generation and Final Output

After injecting the model lists, the script calls generate_toc() to create a markdown table of contents based on the document headers. It replaces the {{TOC}} placeholder with this generated navigation element.

The final step writes the processed content to the repository root. The script outputs to README.md (one directory up from src/) as shown at src/pull_available_models.py#L65-L67, with a confirmation log line signaling successful completion.

CI/CD Automation

The automation executes through GitHub Actions configured in .github/workflows/update-readme.yml. The workflow triggers on every push to the repository and runs the script with the command python -u src/pull_available_models.py at line 43 of the workflow file, ensuring the documentation remains synchronized with provider APIs without manual intervention.

Summary

  • Environment setup uses dotenv and dynamic script_dir resolution to prepare the execution context according to src/pull_available_models.py#L22-L24
  • Provider fetchers implement dedicated functions like fetch_groq_models() that query live APIs and return normalized metadata with rate limits
  • Data aggregation combines results alphabetically into model_list_markdown and trial_list_markdown strings within the main() function
  • Template processing injects content into src/README_template.md via placeholder replacement for {{MODEL_LIST}}, {{TRIAL_LIST_MARKDOWN}}, and {{TOC}} at src/pull_available_models.py#L53-L63
  • Continuous integration runs the pipeline automatically on every push via .github/workflows/update-readme.yml#L43

Frequently Asked Questions

Which LLM providers does the script support?

The script supports Groq, Kluster, OpenRouter, Cloudflare, Hyperbolic, and other providers listed in the main() function. Each provider has a dedicated fetch_*_models() function that handles its specific API endpoint, normalizing responses into dictionaries containing id, name, and limits fields.

How does the script update the README.md file?

The script reads src/README_template.md, replaces the placeholders {{MODEL_LIST}}, {{TRIAL_LIST_MARKDOWN}}, and {{TOC}} with generated markdown content, and writes the result to the repository root as README.md according to src/pull_available_models.py#L65-L67.

Can I run the update script locally for testing?

Yes. Execute the script from the repository directory using:

python -u src/pull_available_models.py

The script loads local environment variables via dotenv, fetches live data from all configured providers, and regenerates the root README.md file with freshly aggregated model information.

Where does the README template reside?

The static template lives at src/README_template.md relative to the repository root. This file contains the structural markdown and placeholder strings ({{MODEL_LIST}}, {{TRIAL_LIST_MARKDOWN}}, {{TOC}}) that the script populates with current provider data.

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 →