This recipe picks which agent backend prompt steps use (cursor, claude, or codex) and which model to ask for. Configuration can live in the workflow file (config { … }) or in the environment. Environment wins over in-file when both are set.
For the full key/default/precedence reference, see Configuration. For credential setup per backend, see Authenticate agent backends.
PATH (cursor-agent for cursor, claude for claude; codex uses HTTP and needs no CLI).Add a module-level config { … } block at the top of your .jh file:
config {
agent.backend = "claude"
agent.default_model = "sonnet-4"
}
workflow default() {
const answer = prompt "Summarize this codebase"
log "${answer}"
}
The valid backend values are "cursor" (the default), "claude", and "codex". The model string is forwarded to the backend — use a name the backend recognizes (e.g. gpt-4o for codex, sonnet-4 for claude).
To use a different backend for one workflow in the same file, add a workflow-level config { … } block (it must be the first non-comment construct in the body):
workflow fast_check() {
config {
agent.backend = "cursor"
agent.default_model = "gpt-3.5"
}
ensure some_rule()
}
Only agent.* and run.* keys are allowed at workflow scope. runtime.* and module.* keys are module-only.
export JAIPH_AGENT_BACKEND="claude"
export JAIPH_AGENT_MODEL="sonnet-4"
jaiph run ./flow.jh
When set, the environment value wins over both the workflow-level and module-level config blocks. The CLI marks each inherited agent/run env var as locked (JAIPH_AGENT_BACKEND_LOCKED=1, JAIPH_AGENT_MODEL_LOCKED=1, …) for the lifetime of that run so in-file overrides never silently take effect.
The codex backend defaults to https://api.openai.com/v1/chat/completions. To target an OpenAI-compatible endpoint:
export JAIPH_CODEX_API_URL="https://api.example.com/v1/chat/completions"
Each prompt step records the resolved backend and model in run_summary.jsonl. After the run, inspect the first PROMPT_START line:
jq -c 'select(.type=="PROMPT_START")' .jaiph/runs/<date>/<time>-<entry>/run_summary.jsonl | head -1
The line includes "backend":"<backend>", "model" (the resolved string, or null when the backend auto-selects), and model_reason (explicit, flags, or backend-default). When model_reason is backend-default, codex still calls the API with gpt-4o even though "model" is null in the summary.