Skip to main content
A Python package orchestrating repository setup, cloud inference, and artifact retrieval Real photography by Alicia Christin Gerald on Unsplash.

gh-ai-runner

Use GitHub Actions as an ephemeral inference backend—straight from Python.

PyPI Python Models License

How it works · Install · Models · API


Overview

gh-ai-runner is a Python orchestration package that turns a GitHub repository into an on-demand AI workload service. Version 0.3 adds concurrent batches, model comparisons, verified result checksums, and privacy-conscious local job metadata on top of the asynchronous 0.2 runtime. The original blocking ai_call() API remains compatible.

No inference server remains online between calls. GitHub supplies the temporary runner; llama-cpp-python executes quantized GGUF weights on CPU.

How it works

sequenceDiagram
    participant App as Python application
    participant API as GitHub API
    participant Repo as Runner repository
    participant Job as Actions runner

    App->>API: Resolve authenticated username
    App->>Repo: Create or reuse repository
    App->>Repo: Sync workflow/script when hashes differ
    App->>API: Dispatch with unique correlation ID
    API->>Job: Start ephemeral Ubuntu worker
    Job->>Job: Restore/download GGUF + run llama.cpp
    Job->>API: Upload output artifact
    App->>API: Poll exact run title or cancel it
    App->>API: Download job-specific JSON artifact
    API-->>App: Return output + usage + resources

Install

pip install gh-ai-runner

Requirements:

  • Python 3.9+
  • GitHub personal access token with repository and workflow access appropriate to the created runner repository
  • GitHub Actions enabled

Quick start

from gh_ai_runner import ai_call

answer = ai_call(
    github_token="your-token",
    prompt="Explain recursion with one small Python example.",
    model="qwen",
    temperature=0.2,
)

print(answer)

The first call creates or configures ai-inference-runner. Later calls skip file commits when the embedded workflow and script hashes match their remote contents.

Asynchronous jobs

submit() returns after dispatch instead of waiting for the model. Each job has a stable ID; retries use distinct correlation IDs such as <job-id>-1 and <job-id>-2.

from gh_ai_runner import GitHubAIRunner, JobStatus, RetryPolicy

runner = GitHubAIRunner(github_token="your-token")
job = runner.submit(
    "Summarize the tradeoffs of SQLite and PostgreSQL.",
    model="qwen",
    retry_policy=RetryPolicy(max_retries=1),
)

print(job.job_id, job.refresh())
result = job.result(timeout=900)
print(result.output)
print(result.usage.total_tokens)
print(result.resources.memory_total_bytes)

job.refresh() is non-blocking. job.wait() blocks until completion, job.result() downloads and parses the structured result, and job.cancel() requests cancellation through GitHub's Actions API. A handle can be reconstructed later with runner.get_job(job_id, attempt=1).

Multiple jobs can safely share one runner repository. Correlation is based on an exact workflow run title and a uniquely named artifact, rather than whichever unseen run appears first.

Bring your own provider key

Version 0.2 supports OpenAI-compatible HTTPS providers. The key is encrypted locally with the repository's GitHub public key and stored only in the dedicated GH_AI_PROVIDER_API_KEY Actions secret. It is never sent through workflow inputs or written to result artifacts.

from gh_ai_runner import GitHubAIRunner, ProviderConfig

runner = GitHubAIRunner("your-github-token")
groq = ProviderConfig.groq("llama-3.3-70b-versatile")

runner.configure_provider(groq, api_key="your-provider-key")
result = runner.submit("Explain B-trees.", provider=groq).result()
print(result.output, result.usage)

There is one dedicated provider-key slot per runner repository in 0.2. Calling configure_provider() again rotates that key. Custom OpenAI-compatible endpoints use ProviderConfig(name, model, base_url); base_url must use HTTPS.

Batches and model comparisons

Batch requests are dispatched independently, then polled concurrently:

from gh_ai_runner import GitHubAIRunner, InferenceRequest

runner = GitHubAIRunner("your-github-token")
batch = runner.submit_batch([
    InferenceRequest("Summarize this release note.", model="tinyllama"),
    InferenceRequest("Write three test cases.", model="qwen"),
])

for result in batch.results(timeout=900):
    print(result.model, result.output)

Use compare() to send one prompt to several distinct local models:

comparison = runner.compare(
    "Explain optimistic concurrency control.",
    models=["tinyllama", "qwen", "phi3"],
    max_tokens=300,
)

for model, result in comparison.results_by_model().items():
    print(model, result.output, result.usage.total_tokens)

BatchJob.refresh(), wait(), results(), and cancel() operate across the complete group while preserving request order. Every group receives a stable batch_id, which is also attached to its jobs and persistent metadata records.

Integrity and persistent metadata

The client and worker independently calculate a SHA-256 digest of the normalized request. The worker also hashes the generated output. The client rejects an artifact when its job identity, request digest, output digest, or algorithm does not match.

Job metadata is stored by default in ~/.gh_ai_runner/jobs.sqlite3. It includes job/correlation IDs, attempts, status, model, provider, run ID, timestamps, token counts, duration, and SHA-256 digests. GitHub tokens, provider keys, prompt text, system text, and output text are never stored in this database.

recent = runner.list_jobs(limit=20)
resumed = runner.resume(recent[0].job_id)
print(resumed.refresh())

Pass metadata_path=None to disable persistence or supply a custom database path.

Models

Key Model GGUF size Default context Good fit
tinyllama TinyLlama 1.1B Chat 0.6 GB 2,048 Fast basic answers
llama Llama 3.2 1B Instruct 0.7 GB 4,096 General instructions
phi3 Phi-3.5 Mini Instruct 2.2 GB 4,096 Stronger reasoning
qwen Qwen 2.5 1.5B Instruct 1.0 GB 4,096 Code and math
gemma2 Gemma 2 2B Instruct 1.6 GB 4,096 Chat/instructions
deepseek DeepSeek-R1 1.5B 1.1 GB 4,096 Deliberative reasoning

Validation caps context at 8,192, generated tokens at 4,096, and temperature between 0 and 2. The package estimates memory from model size plus extra context before dispatch.

Compatibility API

ai_call(
    github_token: str,
    prompt: str,
    model: str = "tinyllama",
    system: str = "You are a helpful assistant.",
    max_tokens: int = 512,
    temperature: float = 0.7,
    cache: bool = True,
    n_ctx: int | None = None,
    repo_name: str = "ai-inference-runner",
    verbose: bool = True,
) -> str

The function internally creates a client, submits a job, waits, and returns InferenceResult.output as a string.

Package architecture

gh_ai_runner/
├── client.py       asynchronous client and secure provider setup
├── job.py          status, waiting, retry, result, and cancellation handle
├── batch.py        concurrent batch and comparison handles
├── metadata.py     privacy-conscious SQLite job metadata
├── integrity.py    canonical request and output digests
├── types.py        typed results, telemetry, policies, and errors
├── core.py         backwards-compatible ai_call wrapper
├── repo.py         repo creation and hash-based file sync
├── runner.py       embedded workflow and inference script
├── models.py       model catalog and resource limits
├── validation.py   parameter and memory validation
├── polling.py      workflow run discovery/completion
├── artifact.py     output download and extraction
└── logger.py       elapsed-time progress reporting

Engineering notes

  • Remote file SHA-256 comparison eliminates unnecessary commits and workflow registration churn.
  • A random job ID is included in run-name; polling requires an exact title match.
  • Retry attempts keep a stable job ID and receive distinct correlation IDs.
  • The worker reports CPU, memory, disk, peak RSS, duration, and model token usage.
  • Local inference automatically assigns CPU threads from the detected runner resources.
  • Provider secrets use GitHub sealed-box encryption and a dedicated secret slot.
  • Batch result waiting is concurrent and preserves submission order.
  • Result identity and SHA-256 checksums are verified before returning output.
  • Persistent metadata intentionally excludes prompt, system, output, and secret values.
  • The package adds a concise/direct instruction to the supplied system prompt.
  • GitHub-hosted CPU inference has meaningful cold-start and generation latency; caches are best-effort.
  • Tokens are passed by the caller and should come from a secret store—not source code.
  • The repository declares version 0.3.0 in both package metadata and the public module.
  • Distribution archives are checked into dist/; releases are a cleaner long-term channel.

Skills demonstrated

Python package design · REST orchestration · CI as compute · idempotent provisioning · content hashing · polling/event correlation · artifact retrieval · resource validation · open-model deployment

Resume-ready highlight

Published a Python orchestration package that provisions and synchronizes GitHub-hosted inference workers, dispatches one of six quantized models, correlates workflow runs, retrieves artifacts, and exposes the entire lifecycle as one typed function call.

License

MIT

Metadata

Release files for gh-ai-runner 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gh-ai-runner 0.3.0
File Size Uploaded Provenance
gh_ai_runner-0.3.0.tar.gz 31.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for gh-ai-runner 0.3.0
File Interpreter ABI Platform
gh_ai_runner-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 60.1 kB

Release files / gh_ai_runner-0.3.0.tar.gz

Download URL gh_ai_runner-0.3.0.tar.gz
Size 31.8 kB
Tags Source
SHA-256 checksum
How to use checksums
4a60238e5cf5d4d261d4d0165b16019a94f3c03c3819509b8fb7d11a33f488f3
BLAKE2b-256 checksum
How to use checksums
92d5804ad07507626259b7d4cbd350fd3adf19962ff1bb4ada2ad14e70ff3c57
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / gh_ai_runner-0.3.0-py3-none-any.whl

Download URL gh_ai_runner-0.3.0-py3-none-any.whl
Size 28.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5ab86e4c13f2891b4e159377e51b2b5d67201da65de26baaaccbe6a3ef8a2f1c
BLAKE2b-256 checksum
How to use checksums
81121fd3fb24b5708c71456c98ea68c07dabdad9d858cbe9b75a3288a713d6e1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Security for gh-ai-runner 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page