Skip to content

Custom harnesses

A CLI harness is a command plus an argument template. Jimothy fills in the template for each step, spawns the command in the run’s workspace, and reads its output. You can add any CLI this way, and every built-in harness is defined with the same fields, so the same knowledge lets you fix a built-in when a CLI changes its flags.

This is the built-in Codex harness, as stored:

{
"command": "codex",
"args": ["exec", "--json", "--full-auto", "--skip-git-repo-check", "{{options}}", "-"],
"modelArgs": ["--model", "{{model}}"], // only added when the step picks a model
"promptVia": "stdin", // or "arg" ({{prompt}}) or "file" ({{promptFile}})
"outputFormat": "codex-json", // or "claude-stream-json" / "pi-json" / "text"
"versionArgs": ["--version"],
"modelListArgs": ["debug", "models"],
"models": ["gpt-6-sol", "…"],
"defaultModel": "gpt-6-sol"
}
  1. Open Harnesses and click Add harness. The editor opens with Name My agent, Type Command-line agent, arguments {{prompt}}, prompt delivery argument and output Plain text.
  2. Fill in the fields below. The Preview at the bottom shows the command line that will run for the default model.
  3. Click Save. Jimothy runs the version check right away; the card shows the version or the error.
  4. In a pipeline, select the new harness on an agent step and run it.
Field Stored as Description
Name name Shown in the step editor and logs. Required.
Type kind Command-line agent (cli) or LLM API (api, see API harnesses).
Description description Shown on the card and as the hint under the step’s Harness menu.
Command command Executable name on PATH, or an absolute path.
Prompt delivery promptVia stdin (default), argument ({{prompt}}) or file ({{promptFile}}).
Arguments args One argument per line. Each line is one argv entry, so no shell quoting is needed or applied.
Model arguments modelArgs Added only when a model is chosen. Placeholder: --model / {{model}}.
System prompt arguments systemPromptArgs Added only when the step has a system prompt. If empty, the system prompt is prepended to the prompt instead.
Subagent arguments subagentArgs Added only when the step attaches subagents. If empty, subagents are ignored.
Output format outputFormat Plain text, Claude Code stream-json, Codex exec –json or Pi –mode json.
Model list source modelListArgs / modelListProvider Where Fetch latest gets models: None, Command (with the args to run), Anthropic API or OpenAI API.
Model list base URL baseUrl For the API sources. Empty = api.anthropic.com or api.openai.com/v1.
Model list API key variable apiKeyEnv Env var holding the key for the API sources.
Version check args versionArgs Used for detection. Default --version. Must exit 0 when the CLI works.
Models models, defaultModel One-click model choices for steps; ★ marks the default.

Arguments, model arguments, system prompt arguments and subagent arguments are rendered with Jimothy’s template engine, with these values:

Placeholder Value
{{prompt}} The rendered prompt (with the system prompt prepended if the harness has no system prompt arguments).
{{promptFile}} Path to a temporary .md file containing that prompt. Written only when Prompt delivery is file or some argument uses {{promptFile}}.
{{model}} The model id for this step: the step’s model, or the harness default.
{{systemPrompt}} The step’s rendered system prompt.
{{subagents}} The attached subagents as one JSON object keyed by name: {"name": {"description", "prompt", "tools"?, "model"?}} (Claude Code’s --agents format).
{{cwd}} The run’s workspace directory (also the process’s working directory).
{{options}} Not a value: a line containing only {{options}} marks where model, system-prompt and subagent arguments are inserted. Without it they’re appended at the end.

Rules worth knowing:

  • An argument that renders to an empty string is dropped. A line {{systemPrompt}} disappears when there’s no system prompt.
  • Partially empty arguments are kept. --model={{model}} becomes --model= when no model is chosen, which most CLIs reject. Put model flags in Model arguments so they’re only added when a model is set.
  • Template filters work here too, e.g. {{model | default:"gpt-5"}}.
  • Prompt delivery only decides whether the prompt is written to stdin. With arg you must put {{prompt}} in an argument, and with file you must use {{promptFile}}, otherwise the CLI never sees the prompt.
  • With stdin, Jimothy writes the prompt and closes stdin. With other modes stdin is closed immediately (a CLI that waits for input then sees end-of-file).
options = modelArgs (if a model is chosen)
+ systemPromptArgs (if the step has a system prompt and the harness defines them)
+ subagentArgs (if the step attaches subagents and the harness defines them)
args = your Arguments, with a lone {{options}} line replaced by options
(or options appended at the end if there's no {{options}} line)

For example, with a step using model gpt-5:

Harness arguments Model arguments Result
run {{options}} {{prompt}} --model {{model}} run --model gpt-5 "<prompt>"
-p {{prompt}} --model {{model}} -p "<prompt>" --model gpt-5
--message-file {{promptFile}} --model {{model}} --message-file /…/prompt-x.md --model gpt-5
Format Use when
Plain text Any CLI. The step output is the whole of stdout with colours stripped. No tool-call structure, cost or tokens.
Claude Code stream-json The CLI emits Claude Code’s --output-format stream-json --verbose events.
Codex exec –json The CLI emits codex exec --json JSONL events.
Pi –mode json The CLI emits Pi’s JSON events.

Structured formats give you tool-call logs, thinking, cost and token tracking. Lines that aren’t valid JSON are still shown as plain output lines. See Output formats.

CLI harnesses receive the step’s environment: the app environment (with the combined PATH), Settings → Environment variables, the project’s env, the step’s Environment, and the FACTORY_* variables. See Environment variables.

A harness definition also has an env field that is merged on top for that harness only, but the harness editor doesn’t expose it. Use Settings → Environment variables or a step’s Environment instead.

A CLI that reads the prompt from stdin and prints the answer:

Field Value
Command my-agent
Prompt delivery stdin
Arguments --non-interactive
Model arguments --model, {{model}}
Output format Plain text

A second Claude Code harness with safer permissions (for example, a read-only reviewer):

Field Value
Command claude
Prompt delivery stdin
Arguments -p, --output-format, stream-json, --verbose, --permission-mode, plan
Model arguments --model, {{model}}
System prompt arguments --append-system-prompt, {{systemPrompt}}
Subagent arguments --agents, {{subagents}}
Output format Claude Code stream-json
Model list source Anthropic API

A wrapper script that takes a prompt file:

Field Value
Command /Users/me/bin/run-agent.sh
Prompt delivery file
Arguments {{promptFile}}, {{cwd}}
Output format Plain text

Built-in harnesses open in the same editor from their pencil button. Saving stores your version and it replaces the shipped one field by field. Common reasons to edit a built-in:

  • A CLI renamed or removed a flag. Update Arguments.
  • You’re running as root and Claude Code refuses --dangerously-skip-permissions. See Claude Code → Running as root.
  • You want a different default model, or a trimmed model list.

The ↺ button (Reset to built-in defaults) throws your version away, including any stored API key and the disabled flag. Built-in harnesses can’t be deleted; disable them with the toggle instead.