Product
The pipeline
A DAG of typed steps, declared in release.yaml and validated against a registry of 42 of them before anything is scheduled. A malformed pipeline fails in half a second with a line number, not twenty minutes into a build.
Validated before it is scheduled
Two passes. The first checks shape against a JSON Schema — types, patterns, enums — and stops there if the document is malformed, because running semantic rules over a broken file produces cascading nonsense. The second checks what a schema cannot express: dependency cycles, cross-references, step lookups, fleet satisfiability, and whether a fork’s build could reach a credential.
Every diagnostic carries a stable code and a source line and column, resolved from the YAML node tree. A code is searchable; “something is wrong somewhere in your config” is not.
Typed steps, and one escape hatch
A step declares what it needs — capabilities, credentials, timeouts, retry class — and three independent subsystems read those declarations: the validator, the scheduler and the secret scoper. That is why a job’s credential set is computable by reading the file rather than by running it.
core/shell exists and is deliberately unergonomic. It is blocked in any job that also distributes, because a shell step in a job holding store credentials is the shape of an incident.
Matrix expansion, capped against reality
A matrix expands to a Cartesian product, and the validator warns when the expansion exceeds what your fleet could plausibly run. On a fleet of two Macs a twelve-way matrix is not parallelism, it is a queue — and finding that out from a warning beats finding it out from a dashboard.
What this part refuses to do
Each of these could be built, and each would make the product worse.
- An expression language in credential requirements
- Requirement conditions are declarative matchers — equals, one_of, present — and nothing else. A job’s credential set must be computable by inspection, which an expression evaluator would end.
- Silently caching dependency counts
- The engine recomputes readiness from the graph rather than decrementing a counter. Counters drift under retries and requeues, and a drifted counter is a job that never starts with nothing to point at.