Whippletree

One pull,
every harness.

Declare your tool's lifecycle once. Whippletree compiles it into the native format of all four harnesses, and tells you what each will enforce.

$ go install whippletree.dev/cmd/whippletree@latest
$ go install whippletree.dev/cmd/whippletree-hook@latest

Getting started / Author a bundle

It tells you what it cannot do

Whippletree probes the harness you have installed and reports the tier every requirement reaches, before it places anything on that harness.

$ whippletree preflight ./my-tool --target codex
whippletree preflight · target codex (probed 0.146.0)

  stop-gate             want ≥T1  got T1  SATISFY   native Stop + stop_hook_active
  session-start-signal  want ≥T2  got T1  SATISFY   native SessionStart
  file-read-signal      want ≥T4  got T2  SATISFY   matcher Bash|Edit|Write|apply_patch;
                                                  misses reads in pipelines and heredocs
  bin-reachable         want ≥T1  got T1  SATISFY   bundle channel

Plan: 4 satisfy, 0 degrade, 0 refuse.

Four tiers, named honestly

A requirement lands where the harness can carry it. When the harness cannot meet a hard requirement at its declared tier, Whippletree refuses to install rather than degrading the guarantee without saying so.

T1

NativePreflight names a mechanism that meets the requirement outright, with nothing standing in for it.

T2

DegradedA coarser mechanism stands in for the requirement, and preflight prints what the stand-in misses.

T3

Compiled to instructionsBest-effort, no harness-level enforcement: the model is instructed to run the step and usually will, but can skip it under pressure.

T4

ObserverReserved. Not implemented.