Skip to content
This text was generated by an LLM (how cgwalters uses LLMs). cgwalters has not reviewed it yet.

The compiler question

Decided, 2026-10-06: none for now. A workflow that uses agentic-job is not generated by a compiler. agentic-job is a binary and a reusable workflow that holds every job of a run, so a caller writes no job of its own around the agent, and that is what the compiler-only rules below protect.

The question was whether what runs should be reviewed generated YAML and never hand-edited YAML. gh-aw requires that, and so did our own proof of concept, workflow-compiler. That repository is to be archived, and its requirements document is now requirements.md, restated for this design and marked where a rule was the compiler's alone. This replaces the earlier decision (tracker#239, 2026-09-30) that made workflow-compiler the home of the code and this repository its documentation.

The decision is revisited if either of these happens:

  • a caller needs privileged steps of its own inside the agent job, which a reusable workflow cannot offer safely;
  • gh-aw upstream takes a runtime that runs the agent as a host user, so that its compiler could generate this sandbox without a fork.

The rest of this page records what was checked in the code of each option.

What a compiler can enforce

A reusable workflow or an action is code the caller calls. It cannot see or constrain the rest of the caller's workflow. A compiler that generates the whole file can. From workflow-compiler's rules (src/shape.rs, lib/gha.ncl and 66 sources its tests require to be rejected), the ones only a compiler gives:

  • no step in the sandboxed phase names a secret or the job's token, in any spelling;
  • the job has no container, services, defaults, job env or step shell that would change how the sandbox is entered;
  • text an outsider controls (a pull request's title, a branch name, an input) is never expanded inside a privileged script;
  • steps that hold credentials read only files the sandbox handed over through the checked path, never a sandboxed step's outputs;
  • every workflow file in the repository is either generated or listed, with a reason, as hand-written;
  • the generated file is byte for byte what the compiler produces from its source, so a hand edit fails a check.

gh-aw's compiler gives a different set: a fixed job graph (agent, threat detection, apply), token permissions for the apply job computed from the enabled output types, and a strict mode that refuses write permissions for the agent, wildcard network access and a disabled sandbox.

What a reusable workflow already gives

When the unit is a whole reusable workflow and not a step, the caller cannot add steps to its jobs, raise its permissions, or reach into its sandbox. It can pass inputs and secrets, and it can pin the workflow by commit. So "the caller cannot weaken the sandbox" holds without a compiler, with two exceptions. An input must not be a way to do it: one that runs the caller's script as root before the sandbox closes would be. The packages and npm inputs come close to that today: sandbox setup installs them as root, before the network rules load, and an npm package's install script runs as root with them. They are the caller's own choice of what to trust, and a caller should not forward them from whoever dispatches a run. And runner labels resolve in the caller's repository, so the caller chooses the machine.

A reusable workflow also has one identity whoever calls it: the forge's identity token for the job names the called workflow file as well as the calling repository. An inference proxy can decide on both. A file generated into each caller's repository has a different identity per repository.

What a reusable workflow cannot do is constrain the jobs the caller writes beside it. That is why the job that applies the outputs, the only one with a write token, is inside agentic-job's workflow and not left to the caller (safe-outputs.md). A checker over the caller's plain workflow files can constrain those jobs, run as a check from the base branch: agentic-job workflows check ports the rules above that do not depend on generated steps.

The options that were not chosen

gh-aw's compiler, with this runtime as its sandbox and engine. Our fork adds a host-user runtime in four commits. It has had demonstration runs only, nothing is proposed upstream, and it was 253 commits behind five days after it was made. gh-aw's strict mode refuses the runtime because it has no egress control, and running the ACP harness as a gh-aw engine is untried. The compiler's main package is about 140,000 lines of Go we would not own.

workflow-compiler, brought back. About 2,000 lines of Rust and 1,200 of Nickel, ours, enforcing the list above. On its main branch it has no inference, no egress control and no safe outputs, and runs only the fake agent. Its source language is one only we use.

Both emit GitHub Actions YAML only, so neither helps on another forge. And a compiler is a second thing to keep correct, with security weight: a bug in it is a bug in every workflow.