Concept 9 of 10

You forked create_pr three times. Write it once instead.

Three repos, three slightly different PR policies, so you copy-pasted create_pr and now you maintain three of them — and you're paying frontier prices for steps a 7B model could do. Write the building block once, compose it anywhere, layer per-project rules on top without forking, and pick the model each step actually needs.

Write the building block once; compose it anywhere

A capability is a reusable building block — a small sub-workflow that does one thing (your create_pr, your verify-tests) behind a typed input/output contract. It keeps its own shared state, the scratchpad each step reads from and writes to as the workflow runs. A larger workflow that wires several capabilities together is the orchestrator; it hands each one its inputs and collects its outputs. Fix a bug in create_pr once and every orchestrator that uses it inherits the fix — no more hunting down three forked copies. Break its contract and every dependent fails at load time, not in production.

flow.yaml
workflows:
  cap.verify.workspace-green:              # a capability: one job, reusable
    snippet:                               # the snippet block IS its typed contract
      inputs:  { repo:  { type: string, required: true } }
      outputs: { green: { type: boolean } }
    # ... its own state machine, with its own shared state

  flow.add-feature:                        # an orchestrator: composes capabilities
    inputs:
      repo: { type: string, required: true }
    states:
      verifying:
        transitions:
          verify:
            target: done
            executor:
              kind: workflow
              definitionId: cap.verify.workspace-green
              use:                         # $.context.* = the orchestrator's shared state
                inputs:  { repo: "$.context.repo" }            # read from shared state
                outputs: { "$.context.workspace_green": green }# write the result back

Layer the rules; don't fork the policy

The reason you forked create_pr in the first place was a per-repo rule — this project squash-merges, that one needs two reviewers. Instead of three copies, the rules layer: your personal defaults, your project's rules, your team's rules — stacked, so a project tweak overrides one rule without forking the whole building block. The shared create_pr stays one definition; each layer only declares what it changes. Fix the base once and every project still inherits it.

The cheapest sufficient model, per step

The model is chosen per step. A trivial classification can run on a small local model; a hard refactor can escalate to a frontier model; a deterministic step needs no model at all. You stop paying frontier prices for work that doesn't need frontier reasoning. You can name a model directly, or tag the step with an affinity: and let models.yaml resolve which model fills it — so swapping models is one file, not a find-and-replace across workflows.

Picking a model per step is a run-mode capability: it works when flowgate drives the loop, not when it sits behind Claude Code or Cursor as a gateway. How to run it lays out which mode does what.

triage.yaml
triaging:
  transitions:
    triage:
      target: triaged
      executor:
        kind: llm
        model: anthropic:claude-sonnet-4-6   # cheapest sufficient model for this step
        prompt_template: |
          Classify the issue in $.context.issue_body. Pick one transition.
        max_iterations: 3

Concept 9 of 10

Next concept →

Harness first. Models second.

The inversion, named: a deterministic harness for nondeterministic intelligence.

See all concepts