By October I had six different ways to run a command called smoke:qc. Two main repositories had step-list runners that had grown apart. Other projects used shell chains, PowerShell, an alias, or no aggregate runner at all. Some of the checks they called were shared, but their ownership was split between aidd and Spernakit.

I had already written about a guard installed in only three of fifty-one repositories. That led to a shared-file manifest. It helped with delivery, but the things being delivered still lived inside products with other jobs to do.

On October 12 I moved the shared checking tools, hooks, installers, and synchronization code into a new repository called Smokestack. aidd kept its orchestration code. Spernakit kept the application template. Neither needed to be the place another project visited to obtain a Git hook.

What a delivered copy can prove

The files still travel into each consumer’s repository. There is no public package to install, and Smokestack had no remote or published release during this work. A checkout of a consumer holds the files its checks run.

Each consumer has a lock recording the groups it takes and the version and commit they came from. Delivered files have hashes and Git modes. A file seeded once and then owned by the application is treated differently from one that must remain identical.

That distinction matters for hooks. A project may already have a hand-maintained chain or another tool’s hook. The sync cannot replace it just because a shared hook exists somewhere else. It also refuses to overwrite uncommitted changes at a target path.

The receiver checks its delivered files against the lock. That tells me whether those files still match the recorded delivery. It doesn’t tell me whether the repository calls them, whether its local configuration includes every needed check, or whether a result from yesterday still applies to today’s code.

Those are separate questions. They need separate evidence.

The command stays local

The runner followed on October 13. It reads the consuming project’s smokestack.json and runs the steps that project names, in order. The full gate continues after a failed step so its summary can name the failures together. The fast subset stops at its first failure.

The project keeps that configuration. Delivering a runner does not decide which application checks belong in a gate, and the sync does not overwrite the step list. StarSync was the first consumer recorded using the replacement runner. Other repositories took their deliveries and adoption checks separately.

Later work added an opt-in step cache. A repository has to declare what a cached step reads; some checks read sibling repositories or external state and must keep running. That is another place where a shared implementation cannot make the application’s decision for it.

The broader fleet was still unfinished at the end of this period. Smokestack could report stale consumer copies while an individual repository’s own checks passed. I want that disagreement visible. It names the remaining delivery work instead of making a local pass stand for a rollout that hasn’t happened.