Skip to content
Insights · Engineering

Which runner did that job use?

Name the runner label that job used, and the machine behind it. A different job can use another label, and another client did not run this one.

Scroll
EngineeringOct 20, 202613 min readBy Salman Naqvi, Founder & CEO
Which runner did that job use?

A job ran against the client's repository, and someone is about to say it ran on the usual machine. Tonight, three proofs, in a repository you or the client can open. Name the runs-on label, and name the runner the log says took the job. Show a different job whose label or runner is not this one. Show another client's repository that does not list this run. If any of the three needs the person who copied the YAML and then left, you have not named the runner. You have a green check and a label that will mean a different machine tomorrow.

This is the machine the job used. It is not the third-party action the workflow fetched. Name the action the workflow runs is the uses line and the ref it was pinned to. A commit SHA on an action is not a runner label, and a runner label does not pin the action. It is not the image the deploy ran. Which image did that deploy run? is a reference and a digest. A digest can be built on one runner and pulled on another. The runner is not the digest. It is not the environment the change was allowed to touch. Which environment got that change? is a target. A production environment is not ubuntu-latest. It is not the file the run kept. Which artifact did that run keep? is a name, a run, and a retention. An artifact can outlive the runner that uploaded it. The file is not the machine.

None of what follows is a finding that this client's jobs are on the wrong machine, and none of it is legal advice. The sizes below are GitHub's current tables for hosted runners, public and private. The percentages below that are a 2026 paper about how workflow files change, not about which runner your job used. A hardware row is not a log line. A share of edits is not a label. They do tell you which numbers people paste onto a job they have not opened.

GitHub's hosted-runner reference prints two standard tables, and the same label is not the same machine. For public repositories, the Linux row that includes ubuntu-latest, ubuntu-24.04, ubuntu-22.04, and ubuntu-26.04 is 4 CPU, 16 GB of RAM, and 14 GB of SSD, x64. For private repositories, the Linux row with those same four labels is 2 CPU, 8 GB of RAM, and 14 GB of SSD, x64. 4 is not 2. 16 GB is not 8 GB. The 14 GB of storage is on both rows. A label of ubuntu-latest does not tell you which row you are on. Public standard runners are free and unlimited. Private standard runners use the account's free minutes and are then charged per minute. The page does not print the per-minute price in that paragraph, so do not invent one. The note above the tables says a -latest image is the latest stable image GitHub provides, and might not be the most recent version of the operating system from the vendor. latest is not newest-from-the-vendor. Beta images are as-is and excluded from the service level agreement (GitHub, GitHub-hosted runners reference).

The macOS rows are a second trap, because two different 14s sit next to each other. On both the public table and the private table, the Intel macOS row is 4 CPU, 14 GB of RAM, and 14 GB of SSD, with labels macos-15-intel and macos-26-intel. 14 GB of memory is not 14 GB of disk, even when the digits match. The Apple silicon row, on both tables, is 3 CPU (M1), 7 GB of RAM, and 14 GB of SSD, and the labels on that row include macos-latest, macos-14, macos-15, macos-26, and xcode-27. 3 is not 4. 7 GB is not 8 GB, and 7 GB is not 16 GB. xcode-27 is a label on that row. 27 is not a CPU count. macos-latest on that row is not ubuntu-latest. The arm64 macOS runners, the page says, do not have a static UUID. Intel Mac runners are assigned a static UDID, and the page prints one: 4203018E-580F-C1B5-9525-B745CECA79EB. That string is a UDID. It is not a workflow label, and it is not a job id. Nested virtualization is unsupported because of Apple's Virtualization Framework. That sentence is a platform limit. It is not a client.

ubuntu-slim is the single-CPU runner, and it is not a small copy of ubuntu-latest. Both tables give it 1 CPU, 5 GB of RAM, and 14 GB of SSD. 1 is not 2, and 1 is not 4. 5 GB is not 7 GB, and 5 GB is not 8 GB, and 5 GB is not 16 GB. The page says single-CPU runners are hosted in a container on a shared VM, while every other standard hosted runner is a new virtual machine. A container is not that VM. The container runs unprivileged: mounting file systems, Docker-in-Docker, and low-level kernel features are not supported. The job timeout for single-CPU runners is 15 minutes, and a job that reaches it is terminated and fails. 15 minutes is not 14 GB. 15 is not the 15 false positives in someone else's table, and it is not a retention in days. Larger runners are a further product, for Team and Enterprise Cloud, with more RAM, CPU, and disk, static IPs, and GPUs. The standard table does not print those larger sizes. Do not promote a phrase into a number the table does not contain.

The image catalog is a third list, and it does not say that every label on a hardware row is one image. The runner-images README maps the Ubuntu 24.04 x64 image to the YAML labels ubuntu-latest or ubuntu-24.04. The Ubuntu 26.04 x64 image is a different row, labeled ubuntu-26.04. The Ubuntu 22.04 x64 image is labeled ubuntu-22.04. The hardware table put ubuntu-latest, ubuntu-24.04, ubuntu-22.04, and ubuntu-26.04 on one specification row. A shared specification is not a shared image. ubuntu-26.04 is not ubuntu-latest on the image README. ubuntu-22.04 is not ubuntu-24.04. The macOS 26 arm64 image is labeled macos-latest, macos-26, or macos-26-xlarge. macos-latest-large is on the Intel macOS 26 row, not on the arm64 row. large is not latest. macos-14 on arm64 is marked deprecated in that README, while the hardware table still lists macos-14 on the standard silicon row. Deprecated in the image repo is not absent from the hardware table. xcode-27-xlarge appears beside xcode-27 on the image row. An xlarge label is not the 3-CPU row (GitHub, runner-images README).

The paper that counted workflow edits did not name this job's runner. Pooya Rostami Mazrae, Alexandre Decan, Tom Mens, and Mairieli Wessel, arXiv:2602.14572v3, 1 March 2026, studied workflow changes from November 2019 through August 2025. The dataset sentence is 267,955 workflow histories from 49,258 repositories, accounting for 3,418,911 workflow file versions. The abstract rounds those to 49K+, 267K+, and 3.4M+. 3,418,911 is what the methods print. 3.4M+ is what the abstract prints. Do not replace one with the other. Repositories contain a median of three workflow files. 3 is a median count of files. It is not the 3 CPUs on the M1 row, and it is not three proofs. Files are updated on average every 159 days, and 7.3% of workflow files change every week. The discussion later says roughly 7%. 7 is not 7.3. 159 days is not 15 minutes (Rostami Mazrae and colleagues, An Empirical Study of the Evolution of GitHub Actions Workflows).

Two adoption sentences use one percentage and two population sizes. The abstract says Decan and colleagues reported a 43.9% adoption rate in a dataset of 68K repositories by the end of January 2022. The related-work paragraph says 70,000 GitHub repositories and 43.9%. 43.9% is printed twice. 68K is not 70,000. Neither population is this client's private repository. The qualitative sample started at 389 files and added 50 more, for 439. 389 plus 50 is 439. They report a margin of error of 4.67% at 95% confidence. 4.67% is not 7.3%, and 95% is not the modification share below. Table 2, on those 439 files, prints 1,109 changes: task specification 441 (39.8%), task configuration 265 (23.9%), documentation 201 (18.1%), runtime configuration 85 (7.6%), execution triggers 46 (4.2%), execution rules 43 (3.9%), and formatting 28 (2.5%). 441 plus 265 plus 201 plus 85 plus 46 plus 43 plus 28 is 1,109. The first three concepts are 81.8%. The last four are 18.2%. 18.2% is not 18.1%.

The same table's change-type row is where one percentage is doing two jobs. Modifications are 53.4%, additions 28.5%, removals 18.1%. 18.1% of changes were removals. 18.1% of changes were also documentation. The digits match. The nouns do not. Do not treat a removal as a comment because the cell is the same, and do not treat a comment as a deletion. Of the 439 commits, 95 (21.64%) touched more than one workflow file. 23 of those were unrelated, 68 were co-changes, and 4 were dependent. 23 plus 68 plus 4 is 95. Of the 68, 31 updated a version, 13 by hand and 18 by a bot, and 37 did something else. 13 plus 18 is 31. 31 plus 37 is 68. A version bump of an action is the neighboring article. It is not a runner.

runs-on is a small cell, and it is still not this job. Table 3 prints runs-on at 1.47% of changes, with additions 2.2% and modifications 95.9%, under runtime configuration. 2.2 plus 95.9 is 98.1, not 100. The page does not print the remainder. Do not invent a removal share to make the row add up. 1.47% is a share of edits in their history. It is not a label, and it is not 7.6%, which is the runtime-configuration concept in Table 2. A concept is not a path. uses is 22.40% of changes and 99.8% of those are modifications. run is 12.99% and 99.7% modifications. 99.8 is not 99.7, and neither is 95.9. Dependabot appears in 69.2% of workflow histories and Renovate in 21.0%. They account for 562,093 of 587,624 version-update modifications. 562,093 is not 587,624. Version tags fell by 7,112 while commit hashes rose by 7,235, described as 239k versus 242k. Fully specified tags rose by 1,434 and major-only tags fell by 667, described as 120K versus 121K. Replacing run with uses happened 9,827 times. Replacing uses with run happened 7,230 times. 7,112 is not 7,230, and 7,230 is not 7,235, and none of those is 9,827. Permission additions were 26,410 at workflow level and 25,708 at job level. 26,410 is not 25,708. A footnote's actions/checkout tag v3.0.0 is a version of an action. It is not a runner label. The paper counted changes to files. It did not open this client's log.

Do the three proofs on one real job, in the repository the client can open. First, the label. Read runs-on. Copy the string. If it is a list of labels, copy the list. ubuntu-latest is not a digest, and it is not 4 CPU until you also know whether the repository is public. If the file does not name a runner, write that. Second, the machine. Open the log for that run and write the runner it names. If the log prints only the label, write that the machine was not stored. A README that maps ubuntu-latest to the 24.04 image is a catalog. It is not this run. Third, the other job. A different job, on ubuntu-slim or on a self-hosted label or on macos-latest, is not this one. If the only way the proof succeeds is to point at a slide, you have not shown a runner. You have shown a drawing.

Three moves feel like the proof and are a second problem. Changing the label after the run, and then describing the new file as what ran. Quoting 4 CPU because the public table is larger, while the repository is private and the private row says 2. Asking a model which runner it was. The model will pick a plausible label from the tables. It will not open the log. The action ref, while the question is which machine ran, is name the action the workflow runs. Pinning a uses line does not name the runner.

The shape of a console that can show one region without opening the next region as the way to prove it is an admin surface, not a YAML label. The Government of Punjab teacher-training platform has an admin console for regional coordinators and region-level dashboards on an AWS backend. The shape that matters here is one region you can point at, distinct from the next region. That case is not a runner ledger. Nothing in the description is a headcount, a duration, or a result figure. If the only screen is a single total for every region, you do not have this proof. You have a sum.

There is a version of this call where hiring someone to build the path is the wrong purchase. You have not sold the work, so there is no client job to name. The client has asked to meet the people who will write the code, and a runner label will not hide that. The thing in the room is a slide, with no workflow behind it. Or the buyer only wants a template of a runs-on line, with no repository to read. A white label software development partner is the wrong purchase for a blank. The criteria for choosing a firm, when you are still choosing, sit on the page for a top SaaS development company. That page is criteria. It does not rank anyone, including us. Or the buyer wants a legal opinion about a runner's terms of service. Hire the lawyer.

When the job is real and the log is not on a screen you can open, the missing object is specific. The label, the runner the log recorded, a different job that did not use it, and another client's repository that does not list the run. A white label software development partner that expects this will put the workflow in the client's repository, before the first billed week, because a label on a laptop you do not hold is not a machine you can name. One that needs a call in order for you to read runs-on is telling you who holds the file. If the first slice is a fixed capability, an AI integration sprint is the shape where the acceptance sentence can include one job whose runner you can read yourself. If nothing has been wired and the question is whether a pipeline could name its runner at all, a two-week AI readiness assessment hands you the findings either way. The findings are yours. They are not 4 CPU, and they are not 1.47%.

The card a charge used, and the thinking budget a request carried, are different objects: which card did that charge use? and which budget did that thinking use?. Do not record either on this page. A last four is not a label. A token budget is not a virtual machine.

Before you tell the client the job ran on the usual machine, do the three proofs and write the label. Name the runner, or write that the log did not store it. Show a different job that did not use it. Show another client's repository that does not hold the run. Do not edit the label and call it the history, and do not borrow 16 GB from the public row when the repository is private. The table is how a label is sized in general. The log is the page you can defend.

Questions

Three records, in a repository the agency or the client can open. The runs-on label, and the runner the log says actually took the job. A different job whose label or runner is not this one. Another client's repository that does not list this run. If the file only names a floating label and the log does not name the machine, write that.

No. A percentage of changes in someone else's history is not the label on this run. A runner you can defend is the label and the machine the log recorded, or a written line that the log did not record it. 1.47% of changes is not ubuntu-latest, and 4 cores on a public repository is not 2 cores on a private one.

When the work is not sold under the agency's name, when the client asked to meet the builders, when the room only has a slide, when the buyer only wants a template, or when the buyer wants a legal opinion.

Find this useful? Tell Google to show you more of it.

Let's put AI to work in your business.

A 30-minute call. You bring the workflow or the roadmap — we'll tell you what's feasible, what it costs, and what we'd build first.

Book a call→