A minimal, agnostic runner for AI-driven development workflows. Declarative workflow format + portable runner with four swappable ports - the primitive, not the product.
jig does not implement an agent. Each step of a workflow is a headless
invocation of the agent harness you already use (claude -p, codex exec,
any CLI that takes a prompt); jig owns the ordering, the retries, the
escalation to humans, the run history, and the cost log.
-
Download a binary from the releases page (or
dune buildfrom source). -
In your repository:
jig init --harness claude --skill-paths ~/.claude/skillsScaffolds
.jig/from the set embedded in the binary: two reference workflows (bugfix,feature-development), their skills, and a working harness preset (claudeorcodex; barejig initwrites a commented template).--skill-pathspoints workflows at an existing skill library. -
Point
.jig/config.yamlat your harness, then:jig validate bugfix jig run bugfix --task "users can't reset their password when ..." jig status <run-id>
A run walks the workflow step by step. Each step's agent ends with a
handoff - status plus a note for the next agent - and jig threads it
into the next step's prompt. Failed steps inside a retry block loop with
their failure notes until the tests pass or the budget exhausts; anything
marked escalate pauses the run for you:
jig run --resume <run-id> --guidance "the fix belongs in the parser, not the lexer"Only the steps that need judgment - diagnosis, design, tradeoffs - need a
frontier model; mechanical steps (running tests, opening a PR) run fine on
a cheaper one. A skill step declares an abstract cost tier, and
config.yaml maps each tier to a concrete harness command, so the
workflow stays portable while the economics stay local:
# workflow # .jig/config.yaml
- skill: implement-fix tiers:
- skill: run-tests mechanical:
until: pass - claude
tier: mechanical - -p
- --model
- claude-haiku-4-5-20251001
# ...A skill can also declare its own default tier in SKILL.md frontmatter; the
workflow step overrides it. A tier the local config does not map falls
back to the default harness (jig validate warns). The run report breaks
cost down per tier:
total cost: $3.6700
by tier: default $3.0400 (4 steps); mechanical $0.6300 (3 steps)
.jig/FIELDGUIDE.md is repo knowledge agents accumulate across runs -
build quirks, hidden dependencies, commands that must run first. When the
file exists, jig injects it into every step's prompt and invites the agent
to append durable learnings; an append mid-run reaches the very next step.
It is a plain repo file: versioned, reviewable in PRs, prunable.
On a TTY, jig run draws the run in place: the pipeline with a spinner on
the active step and per-step durations, costs, and tiers, and beneath it a
live tail of what the running step's agent is doing - titled with the
step, its forEach item, and the tier it runs on.
When the run ends, the completed pipeline stays in the scrollback above the
run report; each step's full output lives in the run record.
jig init # scaffold .jig/ from the embedded starter set
jig run <workflow> --task "<description>" # execute a workflow against a task
[--isolated] # in a git worktree per run
[--detach] # survives its terminal; steps stream to runs/<run-id>.log
jig run --resume <run-id> [--guidance "…"] # continue a paused run
[--skip] # a human finished the paused step; record it and move on
jig attach <run-id> # open the paused step's session; exiting the chat hands back
jig watch <run-id> # attach the live view to a running (or finished) run
jig status <run-id> [--json] # inspect a run
jig list workflows|runs [--json] # discover what is runnable, and what ran
jig validate <workflow> # lint before running
.jig/
config.yaml # harness command, cost tiers (+ optional sandbox wrapper)
FIELDGUIDE.md # repo knowledge agents accumulate across runs
skills/<name>/SKILL.md
workflows/<name>.yaml
runs/ # one JSON record per run + metering.jsonl
Everything is a file: skills and workflows are versioned with the code they operate on, run records are plain JSON a GUI could be built against, and the binary has no other state.
Most ways to run a multi-step agent task keep the plan inside the harness: the model picks the next step turn by turn, or a harness-native script orchestrates workers in-process. jig moves the plan out of the harness and into a file.
| Prompt the agent | Harness-native orchestration | jig | |
|---|---|---|---|
| Who holds the plan | the model, turn by turn | the harness | files you own |
| What runs a step | the agent | one or more agents, in-process | any agent CLI, as a subprocess |
| Where run state lives | the context window | harness memory, session-scoped | files on disk |
| Human mid-run | reprompt and retry | not until it returns | pauses for a human, then resumes |
| Repeatable artifact | none | a script tied to one harness | a workflow file you can commit and reuse |
The trade: jig gives up in-process speed and large parallel fan-out for a portable definition, durable run history, and a human-in-the-loop pause that survives the terminal.
skills/jig/ teaches an agent harness to operate the binary instead of you typing the verbs.
Install by copying it where your harness discovers skills - for Claude Code:
mkdir -p ~/.claude/skills && cp -R skills/jig ~/.claude/skills/ # every project
mkdir -p <repo>/.claude/skills && cp -R skills/jig <repo>/.claude/skills/ # one projectThe skill turns a ticket into a supervised run: condense the ticket into a task, validate, launch with --detach, poll jig status --json, triage pauses (answer derivable questions itself, surface the rest verbatim), and report the outcome with cost and artifacts.
It never executes a workflow's YAML by hand - the run record, metering, and resume semantics exist only through the binary.
Four ports (Executor, ModelProvider, Metering, Store) behind module
signatures with boring local defaults: subprocess, config lookup, JSONL,
filesystem. Isolation is Executor configuration (--isolated runs in a git
worktree per run; an optional config wrapper prepends an OS sandbox to
every invocation). The workflow schema is deliberately frozen at ordered
steps + on_fail + bounded retry, extended by recorded decision with
context: (constant per-workflow framing), with: (literal step inputs),
and forEach: (bounded fan-out over a checked-in items file) - data
binding, not control flow; intelligence lives in skills, not in YAML.
