Skip to main content

Compile and prove the fastest trustworthy baseline for a GitHub repository.

Project description

gh-freshclone

gh-freshclone is a baseline compiler for unfamiliar public GitHub repositories and local Git checkouts. Before a human or coding agent starts editing, it answers:

What is the fastest trustworthy check for this exact commit, does it pass from a clean checkout, and what evidence produced that conclusion?

It compiles repository-owned manifests into an evidence-backed plan, executes the plan without host credentials in an OCI container, and writes a reusable JSON receipt. It distinguishes repository test failures from runner failures and missing environment capabilities.

Automatic detection covers root-level Python, Node.js/Bun/Deno, Rust, Go, Maven, Gradle, Ruby/Bundler, Composer/PHPUnit, CMake, Make/configure, and .NET projects. An operator can apply the same detector to one exact monorepo component, while a repository-owned configuration compiles fully custom steps. The package is alpha software.

Why it exists

  • Readiness graders inspect files but generally do not prove a baseline.
  • Local GitHub Actions runners reproduce workflows, not the smallest useful contributor baseline.
  • Environment generators create an environment but do not record whether the baseline was green.

gh-freshclone is deliberately narrower. It resolves an immutable commit, selects a profile, fingerprints dependency inputs, prepares dependencies with network access, then runs the inferred test in a separate container under its declared network policy. It records the exact image digest, runner version, phase timings, diagnostics, and logs.

Its differentiated use case is the pre-edit external-repository check: an OSS contributor or coding agent often cannot add a task contract to the target repository and should not mutate it just to learn whether its current baseline is green. gh-freshclone produces that evidence directly from a remote exact commit, with zero target-repository configuration for supported stacks.

This is not a general repo-readiness score, service orchestrator, toolchain provisioner, or organization-policy platform. Contract-first readiness tools are a better fit when the repository owner wants to model services, environments, and long-lived workflows. gh-freshclone is the smaller credential-free proof primitive that an external agent can call before making its first edit.

Install

Prerequisites:

  • Python 3.11 or newer and uv
  • Git
  • Docker, Podman, or Apple container 1.0.0+ on a supported Mac

Try the PyPI release without installing it or executing repository code:

uvx gh-freshclone plan pallets/itsdangerous

This resolves an immutable public commit and prints the baseline it would run. Replace plan with doctor to verify local runner readiness, or with check when you are ready to execute the baseline in an isolated container.

Install the command from PyPI:

uv tool install gh-freshclone
gh-freshclone doctor

The signed GitHub release tag is also an immutable source-install option:

uv tool install "gh-freshclone @ git+https://github.com/yhay81/gh-freshclone.git@v0.19.1"
gh-freshclone doctor

doctor verifies Git and runner-daemon readiness, not only whether the executables are present. Public GitHub resolution uses credential-free HTTPS; no GitHub token, API quota, or gh auth login is required. Use doctor --json in automation.

During development:

uv sync --locked
uv run gh-freshclone doctor

The supported interface is the standalone gh-freshclone executable. GitHub CLI extension packaging is not currently claimed.

Quick start

Inspect a plan without executing repository code:

gh-freshclone plan pallets/itsdangerous
gh-freshclone plan owner/repo --ref v1.2.3 --profile reproduce
gh-freshclone plan owner/repo --component apps/web
gh-freshclone plan https://github.com/owner/repo/pull/123
gh-freshclone plan . --json

Automatic planning reads the immutable Git tree, then hydrates only the committed manifests and evidence files used by detection. It does not download the repository's source and test bodies. check expands that same credential-free checkout to the complete exact commit only after it has found an executable baseline. With --component, planning hydrates only bounded inputs below that directory and execution expands only that component from the exact commit, avoiding unrelated monorepo I/O and host-incompatible paths. A component-owned .gh-freshclone.toml can reference arbitrary files inside that bounded component.

Read the upstream GitHub CI state for the same exact commit without executing repository code:

gh-freshclone github-status owner/repo
gh-freshclone github-status owner/repo --ref FULL_40_CHAR_SHA
gh-freshclone github-status https://github.com/owner/repo/pull/123 --json

Execute the default quick baseline:

gh-freshclone check pallets/itsdangerous
gh-freshclone check https://github.com/owner/repo/commit/FULL_40_CHAR_SHA
gh-freshclone check https://github.com/owner/repo/pull/123
gh-freshclone check . --runner docker --cpus 4 --memory 8g
gh-freshclone check owner/repo --component apps/web
gh-freshclone check owner/repo --test-network enabled
gh-freshclone check owner/repo --json

Profiles make the cost/coverage choice explicit:

Profile Purpose Typical policy
quick Fast trustworthy pre-edit signal One compatible tox environment; primary test script
reproduce Repository-default contributor baseline Default tox/test command
full Broad pre-submit confidence All known scripts, features, or environments

The component, profile, preparation and test commands, operator-selected test-network policy, supporting manifest evidence, and dependency fingerprint are part of the plan digest. Test containers stay offline by default even when repository-owned configuration requests network. --test-network enabled is the explicit operator opt-in that enables outbound access for every test step; the effective policy is visible in plan, receipts, and results. Offline and network-enabled PASS indexes are separate and cannot satisfy one another. A PASS is reused only for the same commit, plan version, execution policy, component, profile, runner, resources, and test-network policy. The index is checked before a new clone, so a known PASS normally returns in well under a second after commit resolution.

Use --no-cache when fresh execution evidence is required. When automation already knows a full 40-character commit SHA, pass it with --ref or paste a GitHub commit URL. Ref resolution then makes no network request; materialization still verifies that the object exists before execution. A pasted pull-request URL resolves its advertised head ref without requiring GitHub API authentication.

github-status is the explicit GitHub REST API integration. It uses API version 2026-03-10 to read the latest GitHub Checks and combined legacy commit status for the resolved public commit. The command makes two unauthenticated, read-only API requests, exposes the remaining API quota, does not retry a rate-limit response, and never executes repository code. GitHub's unauthenticated public-data limit is currently 60 requests per hour per source IP. The mutable upstream CI observation is intentionally separate from plan, receipt, and PASS-cache identity.

The ordinary plan and check paths continue to use credential-free Git smart HTTP and do not require a GitHub API quota or token. See the GitHub integration note for API boundaries and Developer Program evidence.

GitHub Action

On a GitHub-hosted Ubuntu runner, the composite action installs the package from the same immutable action ref and writes the complete JSON result to an output path. It needs no checkout, GitHub token, secret, or write permission for a public remote target:

permissions: {}

jobs:
  baseline:
    runs-on: ubuntu-latest
    steps:
      - id: baseline
        uses: yhay81/gh-freshclone@v0.19.1
        with:
          repository: pallets/itsdangerous
          ref: 672971d66a2ef9f85151e53283113f33d642dabd
      - name: Retain the proof even when the baseline fails
        if: always()
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0 # v7.0.1
        with:
          name: gh-freshclone-result
          path: ${{ steps.baseline.outputs.result-path }}

Inputs also expose component, profile, runner, test-network, no-cache, cpus, and memory. GitHub expressions enter the fixed Python entrypoint only through environment variables; it invokes uvx without a shell, places the repository after an option delimiter, and removes Git and GitHub credential variables from the child environment. The action requires a Linux job with Docker or Podman. Use the standalone CLI for Windows, macOS, or Apple container.

What a result means

The result taxonomy is intentionally small:

Status Meaning
PASS Every compiled step passed
TEST_FAILURE The repository baseline executed and failed
ENVIRONMENT_GAP Required executable, library, or permission is absent
INFRA_FAILURE The OCI runner or image could not execute the plan

For implicit environment failures, the tool does not rely on a test name alone. It extracts executable candidates from failing selectors, then probes the same content-addressed image. A diagnostic includes its confidence, evidence, and a package hint when known.

Example:

Result:     ENVIRONMENT_GAP
  python: environment_gap
    Failing tests reference an executable absent from the image: less
    (suggested package: less)

CLI exit codes are stable:

Code Meaning
0 The check passed, the plan has executable steps, or diagnostics are healthy
1 A baseline did not pass, no plan step was detected, or doctor found a missing prerequisite
2 The request, repository, configuration, or runner could not be initialized

After argument parsing, commands invoked with --json also return code-2 initialization failures as a JSON error envelope on standard output:

{
  "api_version": 1,
  "status": "error",
  "error": {
    "code": "initialization_error",
    "message": "failed to pull image ..."
  }
}

Reproducibility and performance

  • GitHub targets are resolved to a full commit SHA using an isolated, credential-free git ls-remote request; exact SHA inputs skip this request.
  • Public targets materialize with a depth-one fetch of only that resolved ref or commit. A ref move falls back to the already-resolved SHA and fails closed if the immutable target is no longer available.
  • Mutable image tags are refreshed from their registry and resolved to repository@sha256:...; a stale local tag is never silently trusted. The digest is used for execution and stored in the receipt. An explicitly declared digest can run from verified local content without a registry round trip.
  • Lockfiles and relevant manifests form a dependency fingerprint.
  • Before any container starts, the exact committed Git tree is streamed from Git objects into one deterministic tar archive. Each prepare/test container extracts that single read-only input instead of copying thousands of host files through a VM bind mount. File modes, symlinks, and commit timestamps are preserved; untracked files and modified working-tree content cannot enter the archive. A small writable .git index/ref layer points at the original checkout's read-only object database, retaining ordinary Git metadata without duplicating its packs.
  • Go reuses module and build caches but compiles go test -count=1, so a fresh proof cannot silently reuse a previous successful test result.
  • Maven and Gradle reuse repository-, image-, and dependency-scoped app-managed volumes. Dependencies are prepared with network access, then the lifecycle is rerun from a fresh read-only checkout with Maven offline mode or Gradle --offline in a network-disabled container. Managed volumes avoid host UID/permission coupling without granting broader container privileges.
  • Ruby/Bundler planning accepts only a generic-platform Bundler 4 lock with complete SHA-256 identities, an exact Bundler version, the official RubyGems source, repository-contained path gems, and a direct locked ordinary test runner. Preparation constructs fixed RubyGems archive URLs from safe lock tokens, downloads them in bounded parallel transfers, and verifies every checksum without evaluating Gemfile, gemspecs, Rakefiles, native extensions, or repository code. The network-disabled test container mounts those archives read-only, installs the exact Bundler into disposable state, performs a frozen local bundle install, and reruns RSpec or the Rake-backed Minitest/test-unit suite.
  • CMake planning requires a literal root CTest signal and refuses a declared minimum newer than its pinned CMake runtime. It conservatively enables one ordinary project test option when the committed option(...) name and description identify it, while excluding CUDA, conformance, sanitizer, benchmark, and integration variants.
  • CMake 3.31.10 and Ninja 1.13.0 are installed into an exact-commit managed volume during the network-enabled preparation phase of a common multi-architecture Python/buildpack image. A configure-only preparation populates declared FetchContent sources in that volume. A fresh configuration, two-worker build, and CTest then run with FETCHCONTENT_FULLY_DISCONNECTED=ON and no container network; compiled outputs are not reused. ctest --no-tests=error prevents a zero-test build from becoming a false PASS.
  • Make planning reads only a root GNUmakefile or Makefile and accepts a literal ordinary test, tests, or check target. If a root configure exists, it must be a bounded UTF-8 sh/bash script. The fixed target runs in the official multi-architecture Buildpack Dependencies Bookworm image with no preparation phase, no credentials, and no container network; documentation, CI snippets, variable-expanded targets, and unknown configure entrypoints are never inferred.
  • Composer planning requires composer.lock, a direct phpunit/phpunit declaration, the matching locked package, and the default vendor/ layout. It rejects locked Composer plugins instead of allowing package code to run during dependency acquisition. The official multi-architecture Composer image installs the exact lock with both plugins and scripts disabled. A second network-disabled container mounts that state read-only, copies vendor/ into its disposable workspace, explicitly disables Composer networking and redundant policy lookups, replays the no-change install lifecycle (including repository autoload/install hooks), and runs the locked vendor/bin/phpunit. Hook and test writes cannot poison the next proof. Missing locked PHP extensions or an incompatible runtime are reported as an environment gap rather than a repository test failure.
  • .NET planning parses one committed root solution without evaluating MSBuild. A declared supported SDK 8/9/10 selects Microsoft's official multi-arch SDK image; quick chooses one ordinary unit-test project and, when a literal matching TFM exists, only that framework. NuGet restore state and generated obj inputs cross the phase boundary in an exact-commit managed volume. The network-disabled test container copies only those restore outputs into a fresh workspace, recompiles the source, and never reuses bin or test results.
  • Canonical CPU and memory limits are recorded in receipt v7 and participate in receipt and PASS-index identity; a proof produced at 2 CPU / 4g is never reused for an 8g request.
  • Download caches are isolated by repository, runner, ecosystem, dependency fingerprint, and resolved image digest. Repository namespaces include a stable hash of the GitHub canonical name or local checkout path, so sanitized display-name collisions cannot share state.
  • Preparation identity includes the dependency fingerprint, resolved image, preparation command, and working directory—not the test command. Changing a test selector does not redownload dependencies, while changing preparation still invalidates the cache.
  • Python .venv/tox state, Node.js/Bun node_modules, and Maven/Gradle dependency state are kept in exact-commit, step-scoped volumes. A success marker allows a fresh proof to skip redundant dependency preparation without treating an interrupted preparation as reusable.
  • A failed preparation discards only its repo/commit/lockfile/image-scoped host cache or prepared volumes before the app performs one clean retry in the same check. This prevents storage-corrupted partial package-manager state from becoming a persistent false repository failure without creating an unbounded retry loop. A second preparation failure leaves the scoped cache clean and returns normally. Test-phase failures retain successfully prepared dependencies for fast deterministic reruns.
  • A successful exact-commit materialization retains only its Git object database, shallow boundary, and target metadata in the bounded host cache. A later fresh proof creates a new Git repository with a generated safe config, rejects links and alternate object stores, verifies retained objects with git fsck --full --strict, and proves the selected component has no missing objects while lazy fetching is disabled. Git config, hooks, credentials, worktrees, test outputs, and mutable refs are never cached. A source object database that cannot fit the shared 5 GiB host-cache budget is not retained.
  • Deno's DENO_DIR, local vendor tree, and node_modules share the same exact-commit volume across the networked preparation and offline test containers, including repositories with "vendor": true.
  • Bun baselines bootstrap a pinned Bun binary into the prepared volume of a Node LTS image. Hybrid test scripts can therefore use bun, node, and npm without a project-maintained custom image.
  • When a Node/Bun package declares an entrypoint that is absent from the checkout and also owns a known build script, that build is compiled before test; committed entrypoints keep the faster test-only quick path.
  • PASS receipts use a versioned pre-clone index.
  • Matching repository/commit/profile/runner probes take a cross-process lock; concurrent agents neither corrupt a shared prepared volume nor duplicate a known PASS build.

On a Windows 11 / Docker 29.6.1 development machine, the pallets/itsdangerous quick profile improved from a 131.7-second full tox run to 5.1–25.2 seconds of runner time across repeated measurements. Reusing its PASS avoids cloning and container startup after immutable-ref resolution. The credential-free default-branch path currently returns in a 0.611-second median over 10 sequential runs. Supplying its exact SHA reduces the median to 0.176 seconds with a 0.204-second p95 for the installed CLI because no remote ref request is needed. A dependency-light entry point returns --version in 53.490 ms median and 63.692 ms p95 instead of loading the execution engine. Below CLI startup, the exact-SHA in-process cache contract measures 2.992 ms median and 4.414 ms p95 over 30 Windows runs. The isolated local-repository hot-path benchmark measures 60.720 ms median and 67.272 ms p95 because local Git metadata and commit resolution use one process. CI fails if the same clone-free path exceeds 250 ms p95 on its Linux runner. These are development measurements, not cross-platform guarantees.

A public-repository trial across eight earlier automatic ecosystems, including the defects discovered during real execution and measured cold/warm results, is recorded in docs/field-trial-2026-07-25.md. On the final dual-build Java target, verified dependency reuse reduced an otherwise fresh end-to-end Maven-plus-Gradle proof from 897.90 to 318.27 seconds while rerunning both offline lifecycles.

The CMake follow-up planned ten current public repositories and accepted eight with root test evidence. A physical proof of fmtlib/fmt@2a2d9edb257322bec0f7ac602fde3b382fe0082a compiled and passed all 21 CTest cases with the test container offline. The first end-to-end check took 175.09 seconds, including 9.97 seconds of fresh preparation and 156.65 seconds of build/test runner time. Reusing that exact PASS returned in 0.42 seconds.

The .NET follow-up accepted all four single-solution repositories in its manifest-only cohort: Polly, AutoMapper, Serilog, and FluentValidation. AutoMapper/AutoMapper@dfa6dd587c5854b4beee5934beb39ba6e9569b84 restored in 44.578 seconds, then compiled and passed 1,217 unit tests in an offline container; total runner time was 72.666 seconds. An intentionally fresh repeat reused only verified restore state, recompiled and reran all tests, and completed in 28.063 seconds. Serilog produced useful negative evidence instead: its exact commit failed restore because its own warning-as-error policy rejected five current high-severity NuGet advisories.

The Composer/PHPUnit follow-up accepted mockery/mockery@3a80322e874fbdce4e87e739456fe48d48a527c8 without repository configuration. Fresh locked dependency preparation took 7.994 seconds; a separate offline container ran 705 tests with 1,105 assertions (10 skipped), and the complete proof took 23.963 seconds. An intentionally fresh repeat verified the prepared-volume marker, replayed the offline install hooks, reran PHPUnit, and completed in 16.661 seconds. ramsey/uuid supplied the fail-closed control: its lock contains four executable Composer plugins, so automatic planning rejected it and named the plugins instead of running them while network access was available.

A fresh probe of public pull request pallets/itsdangerous#428 resolved its advertised head commit without GitHub API authentication, compiled one Python step, prepared dependencies, and passed the test in a second network-disabled container. An earlier execution-policy-v13 cold proof took 9.327 seconds of runner time; an intentionally fresh second proof reused the verified preparation and took 5.077 seconds while still rerunning all 297 tests offline. This is the same pasted-PR workflow exposed by the CLI, not a fixture-only code path.

Run the performance contract against any committed local checkout:

uv run python -m benchmarks.cached_workflow . \
  --runner docker --iterations 30 --max-p95-ms 250
uv run python -m benchmarks.cli_startup --max-p95-ms 250

The Python runner uses an exact-version uv derived image, so it avoids installing the package manager on every run.

Cache operations

Cache locations:

  • macOS: ~/Library/Caches/gh-freshclone
  • Linux: ${XDG_CACHE_HOME:-~/.cache}/gh-freshclone
  • Windows: %LOCALAPPDATA%\gh-freshclone

Set GH_FRESHCLONE_CACHE to override the host location.

gh-freshclone cache status
gh-freshclone cache status --json
gh-freshclone cache prune
gh-freshclone cache prune --max-gib 3 --max-volume-gib 2 \
  --max-volumes 12 --max-age-days 14
gh-freshclone cache prune --max-evidence-gib 0.5 --max-evidence-entries 256

Automatic maintenance runs daily, and also after dependency, immutable-source, or prepared-volume growth crosses its hard limit. Cache hits do not pay for this extra measurement. Defaults are a shared 5 GiB and 128-entry budget for host dependency and exact-source caches, 1 GiB and 512 receipt/log evidence bundles, 24 prepared volumes with a 3 GiB measured-volume budget, and 30 days. A cache hit refreshes its receipt or source LRU time. Docker and Podman volume usage comes from runner metadata without mounting or executing cached content; Apple container retains the count and age limits when byte accounting is unavailable. Runner readiness, version, image/volume metadata, volume creation, failure diagnostics, cache metadata, and cleanup calls are limited to 15 seconds, so a stopped runner cannot turn startup, doctor, cache status, or failure handling into an unbounded wait. Independent version/readiness probes run concurrently while preserving runner preference order, so the worst-case wait does not multiply by the number of installed runners. Image downloads and repository prepare/test phases keep their normal completion semantics. Non-zero runs explicitly retry named container cleanup, and Docker/Podman execution containers carry app ownership labels for diagnosis.

Before a cache-miss execution, the app preserves 2 GiB free on the filesystems holding its cache and temporary checkout. It first removes only reclaimable app-owned cache, tightening the measured prepared-volume budget further when the normal limits are not enough; if the reserve is still unavailable, the check stops before cloning with an actionable error. An existing immutable PASS receipt remains usable because it needs neither a checkout nor a container. Evidence from incompatible receipt/execution-policy versions, dangling PASS indexes, and interrupted-run logs are recovered by the same maintenance path. It never invokes a global runner prune. Removal is limited to host paths below the app cache root and named volumes recorded by this app with the strict ghfc-* format. Per-resource OS locks protect every in-use dependency cache, exact-source object cache, receipt/log bundle, and prepared volume from automatic or manually invoked pruning, including from another process. Unrelated repositories remain parallel. Each step log is capped at 10 MiB while runner output continues to be drained; a truncation marker and diagnostic tail remain available.

macOS, Windows, and Linux

Plan compilation works natively on all three platforms:

Host --runner auto preference
macOS Apple container, Docker, Podman
Windows Docker, Podman
Linux Docker, Podman

auto skips a stopped Docker/Podman daemon when another installed runner is ready. If all daemons are stopped, an existing pre-clone PASS remains available; a cache miss stops before cloning with an actionable readiness error.

Apple container runs Linux containers in lightweight virtual machines. Apple silicon with macOS 26 is the supported configuration. Version 1.0.0 or newer is required because the runner contract uses stable capability, read-only mount, named-volume, no-network, and resource-limit flags. Apple container accepts whole-number CPU limits; Docker and Podman also accept fractional values. Intel Macs and older macOS releases can use Docker or Podman.

gh-freshclone check owner/repo --runner container
gh-freshclone check owner/repo --runner docker

Command construction, read-only input, prepared volumes, and --network none are covered by the cross-platform contract suite. A manually dispatched apple-container-e2e.yml workflow runs the complete prepare-then-offline-test probe on a dedicated self-hosted runner labelled gh-freshclone-apple-container. GitHub-hosted macOS runners cannot provide this proof because nested virtualization is not supported. The ordinary CI workflow additionally runs the CMake, Make/configure, .NET, Composer/PHPUnit, and Ruby/Bundler offline-boundary E2Es on native GitHub-hosted ubuntu-24.04-arm runners. This continuously verifies the same arm64 OCI images and dependency paths used by Apple silicon, while the self-hosted workflow retains coverage of Apple container itself. A physical Apple silicon run and cold/warm public-repository measurements are recorded in docs/field-trial-2026-07-25.md.

Security model

Repository tests execute untrusted code. gh-freshclone therefore:

  • creates a fresh checkout pinned to an exact commit;
  • excludes uncommitted and untracked local files;
  • resolves public GitHub refs with a fixed HTTPS URL, isolated empty Git configuration, disabled prompts, and no API token;
  • uses credential-free HTTPS for public GitHub clones and refuses known private repositories;
  • disables system/global Git config, checkout templates, interactive credential helpers, system attributes, and host-configured filters during materialization;
  • restores cached exact-source objects only into a newly initialized credential-free repository after strict Git object and component-closure validation, without retaining Git config, hooks, alternates, or refs;
  • never forwards GH_TOKEN, GITHUB_TOKEN, SSH agents, Git configuration, or the broad host environment;
  • gives each phase a disposable workspace extracted from one exact-commit archive, with a compatibility fallback to the read-only /input copy only when the committed tree cannot be represented portably;
  • mounts /input read-only with every supported runner;
  • mounts only repository-scoped dependency caches;
  • runs dependency preparation with network access, exits that container, and starts a distinct test container with network disabled by default;
  • never lets repository-owned configuration enable outbound test access by itself; only the caller's --test-network enabled opt-in can do so;
  • drops capabilities, restoring only CHOWN and FOWNER for package extraction;
  • enables no-new-privileges with Docker and Podman;
  • limits CPU and memory on every runner, and process count on Docker/Podman;
  • mounts /tmp as a disposable tmpfs on every runner;
  • removes named test containers on normal completion, error, or interruption.

Only dependency preparation normally needs outbound network access. For a suite that intentionally downloads assets during its test phase, inspect the plan and pass --test-network enabled. A repository may request the same policy in .gh-freshclone.toml, but that request remains offline until the operator explicitly opts in. An OCI runtime remains a security boundary with a non-zero attack surface. Do not add credential or broad host mounts for untrusted repositories.

Detection policy

Commands come only from known manifest structures. README snippets and arbitrary GitHub Actions run blocks are not executed.

Current evidence sources include:

  • Python: pyproject.toml, uv.lock, dependency groups/extras, tox and pytest; legacy setup.py/setup.cfg projects and common requirements-file names are also compiled without executing setup.py on the host
  • Node.js: packageManager, lockfiles, and known package scripts
  • Rust: Cargo.toml and rust-toolchain.toml
  • Go: go.mod, using its explicit toolchain when present and a refreshed stable image otherwise
  • Maven: pom.xml, an optional committed mvnw, and wrapper configuration; test is the default lifecycle and full compiles verify
  • Gradle: committed build files plus a committed gradlew; wrapper compatibility and literal Java 17/21/25 toolchain declarations select a multi-architecture official Gradle image, while unwrapped builds are never auto-run
  • Ruby/Bundler: Gemfile, an exact Bundler 4 Gemfile.lock with complete SHA-256 checksums and a generic ruby platform, and a direct locked RSpec suite or Rake-backed Minitest/test-unit task; Git/plugin sources, custom gem servers, escaping path gems, checksum gaps, and transitive runners are reported rather than executed
  • Composer/PHPUnit: composer.json, an exact composer.lock, a direct locked phpunit/phpunit package, and an optional phpunit.xml(.dist); custom vendor/bin layouts, locks missing the declared runner, transitive runners, and executable Composer plugin graphs are reported rather than guessed or executed
  • Make/configure: one root GNUmakefile or Makefile with a literal test, tests, or check rule, plus an optional root sh/bash configure; the selected fixed command runs only in a network-disabled official buildpack container; quick prefers the conventional check target while reproduce/full prefer test, and a supported CMake plan takes precedence to avoid duplicate native builds
  • .NET: one root .sln or .slnx, optional global.json, and statically listed project paths; quick selects one ordinary unit-test project while rejecting benchmark, integration, performance, sample, and utility projects

Cargo members declared by a root workspace are covered by its cargo test --workspace step. Other nested manifests are reported as not auto-run rather than guessed. When an operator already knows the intended, self-contained boundary, --component applies the same automatic detector there without changing the target repository:

gh-freshclone plan dependabot/dependabot-core \
  --ref 6c8bb8bd9cb7ec79c324bc550a992ab66201e76a \
  --component npm_and_yarn/helpers
gh-freshclone check dependabot/dependabot-core \
  --ref 6c8bb8bd9cb7ec79c324bc550a992ab66201e76a \
  --component npm_and_yarn/helpers \
  --test-network enabled

Component paths are non-empty portable POSIX paths, cannot traverse outside the repository or enter .git, and must name a committed directory. The selected component becomes part of every plan and cache identity. Planning does not recursively guess components; the caller must supply the exact boundary. Execution materializes and archives only that component, preserving its repository-relative path and an exact detached HEAD. If a baseline needs files outside that directory, select a wider component or use a repository-owned root configuration.

A monorepo can instead opt into multiple explicit, reviewable steps with .gh-freshclone.toml:

version = 1

[[steps]]
profiles = ["quick", "reproduce", "full"]
path = "services/api"
ecosystem = "python"
image = "ghcr.io/astral-sh/uv:0.11.32-python3.13-trixie"
prepare_command = "uv sync --frozen --group test"
command = "uv run --offline --no-sync --group test pytest -q"
test_network = "none"
dependency_files = ["uv.lock"]

[[steps]]
profiles = ["full"]
path = "apps/web"
ecosystem = "node"
image = "docker.io/library/node:24-bookworm"
prepare_command = "npm ci --no-audit --no-fund"
command = "npm test"
test_network = "none"
dependency_files = ["package-lock.json"]

The configuration is authoritative when present. Paths and dependency files must remain below the repository, unknown fields fail closed, and plan still does not execute commands. test_network = "enabled" is only a repository request: the effective policy remains none unless the caller passes --test-network enabled. This prevents an unfamiliar repository from granting itself outbound access. The compiled plan records working_directory separately, and the runner mounts each prepared environment at that exact subdirectory rather than relying on a shell-only cd.

Agent and Tsumugi integration

The library API avoids scraping human CLI output:

from pathlib import Path

from gh_freshclone.api import (
    compile_materialized_checkout,
    probe_repository,
    receipt_schema,
)
from gh_freshclone.integrations.tsumugi import outcome_to_tsumugi_flags
from gh_freshclone.model import Repository

outcome = probe_repository(
    "dependabot/dependabot-core",
    ref="6c8bb8bd9cb7ec79c324bc550a992ab66201e76a",
    component="npm_and_yarn/helpers",
    test_network="enabled",
    profile="quick",
    echo=False,
)
assert outcome.api_version == 1
print(
    outcome.status,
    outcome.receipt_path,
    outcome.cached,
    outcome.elapsed_seconds,
)
tsumugi_flags = outcome_to_tsumugi_flags(outcome)

# A host system can retain its own clone and sandbox lifecycle.
repository = Repository(
    display_name="owner/repo",
    commit_sha="0" * 40,
    ref="main",
    source_url=None,
    github_repository="owner/repo",
    local_path=None,
)
plan = compile_materialized_checkout(Path("/exact/checkout"), repository)
schema = receipt_schema()

compile_materialized_checkout only compiles manifests; it does not execute repository code. The caller guarantees that the checkout matches the supplied commit. This is the integration seam for Tsumugi: share the compiler and evidence contract while Tsumugi retains its systemd sandbox, stall detection, rate controls, and state database. outcome_to_tsumugi_flags maps status, commands, commit, diagnostics, image identities, and cache evidence to Tsumugi's existing test_cmd / baseline_* flag contract; it does not bypass Tsumugi's quality gate or external-action controls.

check --json adds api_version, receipt_path, cached, and end-to-end elapsed_seconds to the receipt shape. Receipt v7 is documented by the bundled gh_freshclone/schemas/receipt-v7.schema.json; v6 remains bundled for existing consumers. It records canonical CPU and memory limits, each step's working directory, whether dependency preparation was reused, and whether immutable source objects came from a git fsck-validated cache; resource limits also scope PASS reuse. The Tsumugi adapter preserves nested working directories and exposes limits and source provenance as baseline_resource_limits, baseline_source_cache_hit, and baseline_source_validation.

Development

uv sync --locked
uv run pytest -q
uv run ruff check .
uv build
uv run python -m benchmarks.cached_workflow . --runner docker
uv run python -m benchmarks.cli_startup

CI runs unit and local-checkout integration tests on Windows, macOS, and Linux. It also runs real Docker prepare/offline-test E2E, native arm64 CMake, Make/configure, .NET, Composer/PHPUnit, and Ruby/Bundler boundary jobs, and the cached-path performance contract. Native Apple container E2E is available through the dedicated self-hosted workflow.

Release process

The tag-triggered release.yml workflow builds and smoke-tests the wheel and sdist, records SHA-256 checksums and GitHub artifact attestations, publishes an independent GitHub release, and uses PyPI's official publishing action to add PEP 740 attestations to the PyPI files. PyPI publication runs only when the repository variable PYPI_TRUSTED_PUBLISHING is exactly true and the pypi environment is connected as a Trusted Publisher; it requires no long-lived publishing token. A vX.Y.Z tag must exactly match the project version.

Before publishing, the workflow reruns tests, lint, the native Docker E2E, and the performance contract. It builds with uv build --no-sources, smoke-tests both the wheel and source distribution in isolated environments, writes SHA-256 checksums, and transfers only that three-file release set to a separate publish job. The publish job rechecks the complete set, then copies only the wheel and sdist into a dedicated PyPI upload directory. The source-running build job has read-only repository access and no OIDC token; only the pypi environment job can create GitHub and PyPI attestations, create a draft GitHub release, and publish through Trusted Publishing. The official PyPA action is pinned to an immutable commit. The workflow exposes the GitHub release only after the optional PyPI step succeeds or is explicitly disabled. Release artifacts can then be checked with:

gh attestation verify gh_freshclone-X.Y.Z-py3-none-any.whl \
  --repo yhay81/gh-freshclone

See CHANGELOG.md for release contents.

Support

Use GitHub Issues for bug reports and support. Successful checks, safe failures, performance observations, and unsupported public repositories are welcome through the structured Field report form; they are the product's zero-telemetry feedback loop. Do not include access tokens, private repository content, or full logs from private projects. Follow the security policy for vulnerability reports. See CONTRIBUTING.md for the development gates and non-negotiable execution boundaries. The support contact is yusuke8h@gmail.com.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gh_freshclone-0.19.1.tar.gz (227.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gh_freshclone-0.19.1-py3-none-any.whl (100.8 kB view details)

Uploaded Python 3

File details

Details for the file gh_freshclone-0.19.1.tar.gz.

File metadata

  • Download URL: gh_freshclone-0.19.1.tar.gz
  • Upload date:
  • Size: 227.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for gh_freshclone-0.19.1.tar.gz
Algorithm Hash digest
SHA256 f01a4ad8361f9c540e75a82cc10bfbd01dd452f2e826e513a32e3f7d1ccf0a70
MD5 390ae8d7db4a0ec3dc302c3a32871a92
BLAKE2b-256 c7b044716e59d6a36dc9a5601ca25d6dc494d1adbae47e7fea473051cfbc6b7c

See more details on using hashes here.

Provenance

The following attestation bundles were made for gh_freshclone-0.19.1.tar.gz:

Publisher: release.yml on yhay81/gh-freshclone

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gh_freshclone-0.19.1-py3-none-any.whl.

File metadata

  • Download URL: gh_freshclone-0.19.1-py3-none-any.whl
  • Upload date:
  • Size: 100.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for gh_freshclone-0.19.1-py3-none-any.whl
Algorithm Hash digest
SHA256 74dcfd718a50d1c08fede6f29e2e7165eb3bdbccc71542f41b6b725ed982cd80
MD5 aa189a2a26a375b351ae5e1c707761ee
BLAKE2b-256 186810284263d17d32a70a92cc49562f44736ed75bec8cca4b9733199ceb4ebf

See more details on using hashes here.

Provenance

The following attestation bundles were made for gh_freshclone-0.19.1-py3-none-any.whl:

Publisher: release.yml on yhay81/gh-freshclone

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page