Deterministic chaining: skip what the LLM doesn't need to decide
You have a deploy pipeline. Lint, test, build, then deploy. The first three steps don't need judgment. They either pass or they don't. But without chaining, the LLM has to babysit every single one.
The round-trip problem
Here's what happens without chaining. The model starts the workflow. Gets back the lint step. Reads the response. Reasons about it. Picks the transition. Submits it. Waits for lint to finish. Gets the result. Reasons again. Picks the next transition. Submits. Waits for tests...
That's three full LLM round trips for steps where there's nothing to decide. Each round trip means:
- Input tokens to re-read the workflow state
- Output tokens to reason about the "choice"
- Network latency for each call
- API cost that scales with conversation length
For a 10-step pipeline where 8 steps are computable, that's 8 unnecessary round trips. Real money, real latency, zero value.
Tag it and forget it
The fix is one field: actor: "deterministic".
lint:
transitions:
run_lint:
target: test
actor: deterministic
executor: { kind: cli, command: lint-check }
test:
transitions:
run_tests:
target: build
actor: deterministic
executor: { kind: cli, command: test-runner }
build:
transitions:
build_artifact:
target: ready_to_deploy
actor: deterministic
ready_to_deploy:
goal: Confirm deployment
guidance: All checks passed. Review before deploying.
transitions:
deploy:
target: deployed
actor: agent
The model calls workflow.start. The runtime sees
that the first state has only deterministic transitions. It
executes lint. Succeeds. Moves to test. Executes. Succeeds.
Moves to build. Executes. Succeeds. Arrives at
ready_to_deploy — which has an agent
transition. The chain stops.
Three executor calls. Zero LLM round trips. One response back to the model with the full chain trace.
What the model gets back
The response includes everything the model needs to make the deploy decision:
- A
chainarray tracing each auto-executed step and its result - A
guidanceobject with thegoalandinstructionsfor the current state - Links to the available transitions — in this case, just "deploy"
The model reads the lint results, test results, build output. It has context for the decision. And it didn't waste tokens getting here.
When things break mid-chain
If the test step fails, the chain stops at the failure. The response includes:
- The partial chain trace — lint succeeded, tests failed
- The error from the failed executor
- A recovery link so the model can retry just the failed step
The model doesn't have to restart the whole pipeline. It sees what worked, what broke, and has a link to try again.
The safety net
Chains have a depth limit: maxChainDepth, default 50.
If your workflow has a cycle of deterministic transitions (it
shouldn't, but mistakes happen), the chain stops at the limit
instead of running forever.
You can set it per workflow:
workflows:
deploy:
maxChainDepth: 20
states: ... When to use it
Any step where the outcome is computable — not a judgment call — is a candidate. Linting, testing, building, data validation, format conversion, notification sending. If a human wouldn't need to think about it, the model doesn't either.
The model's time is expensive. Spend it on decisions that matter.
See the full chaining guide or explore the deploy-pipeline example.