---
url: https://salimhamed.github.io/jigs/api/steps.md
---
# steps

Build a factory's own agent step. `createAgentRunner` opens a harness the way the built-in
agent step does and hands back the live provider model.

Call these inside a factory-owned `"use step"` function, never from a workflow. `Driver`,
`DriverContext`, `AgentRunner` and the types they reach are a published contract: a change to
any of them is a breaking release.

## Classes

### AgentSessionError

A durable agent session is missing or cannot be resumed by this harness.

#### Extends

* `Error`

#### Properties

| Property | Type | Default value |
| :------ | :------ | :------ |
|  `name` | `"AgentSessionError"` | `"AgentSessionError"` |

## Interfaces

### AgentRunner

A harness ready to run in a worktree, from [createAgentRunner](#createagentrunner). Pass `model` to the AI
SDK's `generateText`, read the session reference from its result with `sessionFrom`, and call
`close` when the call is done.

#### Properties

| Property | Type | Description |
| :------ | :------ | :------ |
|  `model` | `LanguageModel` | The live provider model, with jigs' policy already applied. |

#### Methods

##### close()

```ts
close(): Promise<void>;
```

Release the worktree lock and stop what the harness started. Safe to call twice.

###### Returns

`Promise`<`void`>

##### sessionFrom()

```ts
sessionFrom(result): AgentSessionRef | undefined;
```

The session reference in a `generateText` result, for a later step to resume.

###### Parameters

| Parameter | Type |
| :------ | :------ |
| `result` | { `providerMetadata?`: `Record`<`string`, `Record`<`string`, `unknown`>> | `null`; } |
| `result.providerMetadata?` | `Record`<`string`, `Record`<`string`, `unknown`>> | `null` |

###### Returns

[`AgentSessionRef`](jigs.md#agentsessionref) | `undefined`

***

### AgentRunnerOptions

Where [createAgentRunner](#createagentrunner) runs a harness, and the session it resumes.

#### Properties

| Property | Type | Description |
| :------ | :------ | :------ |
|  `cwd` | `string` | The worktree the agent works in. |
|  `resume?` | [`AgentSessionRef`](jigs.md#agentsessionref) | A session reference from an earlier call to resume. |
|  `run` | [`RunMetadata`](#runmetadata) | The run the step belongs to: `getWorkflowMetadata()` inside the step. |

***

### Check

One requirement check with a stable id and a label for reports.

#### Properties

| Property | Type |
| :------ | :------ |
|  `id` | `string` |
|  `label` | `string` |

#### Methods

##### run()

```ts
run(): Promise<CheckResult>;
```

###### Returns

`Promise`<[`CheckResult`](#checkresult)>

***

### Driver

How jigs runs one harness or model-source kind: its checks, the environment
it may see, and how it asks, runs or opens a provider model. Each kind a
descriptor can name has exactly one driver inside jigs; a factory cannot
register another.

#### Remarks

A factory reads this to know what `createAgentRunner` does before it
hands back a model. The shape is a published contract: changing it is a
breaking release.

#### Type Parameters

| Type Parameter |
| :------ |
| `K` *extends* [`HarnessKind`](jigs.md#harnesskind) | [`ModelKind`](jigs.md#modelkind) |

#### Properties

| Property | Type | Description |
| :------ | :------ | :------ |
|  `displayName` | `string` | - |
|  `family` | `K` *extends* `"claude"` | `"codex"` | `"pi"` ? `"harness"` : `"model"` | - |
|  `kind` | `K` | - |
|  `minimumVersion?` | `string` | - |
|  `sessionPointer?` | `object` | - |
| `sessionPointer.field` | `string` | - |
| `sessionPointer.providerKey` | `string` | - |
|  `setsEnv` | readonly `string`\[] | Names the driver sets in the harness environment itself, such as a private home. |

#### Methods

##### ask()?

```ts
optional ask(request, context): Promise<ExecutorGeneration>;
```

###### Parameters

| Parameter | Type |
| :------ | :------ |
| `request` | | [`AgentRequest`](jigs.md#agentrequest) | [`ModelRequest`](jigs.md#modelrequest) |
| `context` | [`DriverContext`](#drivercontext) |

###### Returns

`Promise`<[`ExecutorGeneration`](#executorgeneration)>

##### decide()?

```ts
optional decide<QUESTIONS>(request, context): Promise<DecisionGeneration<QUESTIONS>>;
```

###### Type Parameters

| Type Parameter |
| :------ |
| `QUESTIONS` *extends* [`JevQuestions`](jigs.md#jevquestions) |

###### Parameters

| Parameter | Type |
| :------ | :------ |
| `request` | [`AskJevOptions`](jigs.md#askjevoptions)<`QUESTIONS`> |
| `context` | [`DriverContext`](#drivercontext) |

###### Returns

`Promise`<[`DecisionGeneration`](#decisiongeneration)<`QUESTIONS`>>

##### descriptorChecks()?

```ts
optional descriptorChecks(source): Check[];
```

###### Parameters

| Parameter | Type |
| :------ | :------ |
| `source` | | `Extract`<[`OpenrouterSource`](jigs.md#openroutersource), { `kind`: `K`; }> | `Extract`<[`OpenaiCompatibleSource`](jigs.md#openaicompatiblesource), { `kind`: `K`; }> | `Extract`<[`OpenaiCodexSource`](jigs.md#openaicodexsource), { `kind`: `K`; }> |

###### Returns

[`Check`](#check)\[]

##### envAllowlist()

```ts
envAllowlist(request): readonly string[];
```

###### Parameters

| Parameter | Type |
| :------ | :------ |
| `request` | [`DriverRequest`](#driverrequest) |

###### Returns

readonly `string`\[]

##### installationChecks()

```ts
installationChecks(): Check[];
```

###### Returns

[`Check`](#check)\[]

##### jitChecks()?

```ts
optional jitChecks(target): Check[];
```

###### Parameters

| Parameter | Type |
| :------ | :------ |
| `target` | [`HarnessTarget`](#harnesstarget) |

###### Returns

[`Check`](#check)\[]

##### open()?

```ts
optional open(target, context): Promise<OpenedModel>;
```

Build the live provider model for a run. Drivers without a provider model implement `run`.

###### Parameters

| Parameter | Type |
| :------ | :------ |
| `target` | [`HarnessTarget`](#harnesstarget) |
| `context` | [`OpenContext`](#opencontext) |

###### Returns

`Promise`<[`OpenedModel`](#openedmodel)>

##### requestChecks()

```ts
requestChecks(request): Check[];
```

###### Parameters

| Parameter | Type |
| :------ | :------ |
| `request` | [`DriverRequest`](#driverrequest) |

###### Returns

[`Check`](#check)\[]

##### resolveExecutable()?

```ts
optional resolveExecutable(env): string;
```

###### Parameters

| Parameter | Type |
| :------ | :------ |
| `env` | `ProcessEnv` |

###### Returns

`string`

##### run()?

```ts
optional run(request, context): Promise<ExecutorGeneration>;
```

###### Parameters

| Parameter | Type |
| :------ | :------ |
| `request` | `Omit`<[`RunAgentOptions`](jigs.md#runagentoptions)<`undefined`>, `"output"`> & `object` |
| `context` | [`DriverContext`](#drivercontext) |

###### Returns

`Promise`<[`ExecutorGeneration`](#executorgeneration)>

***

### DriverContext

What a driver receives for one call: the run it belongs to, the harness
environment jigs built for it, and, for a structured call, the output spec a
provider model consumes. `deps` is jigs' own wiring, not part of the contract.

#### Properties

| Property | Type |
| :------ | :------ |
|  `env` | `Record`<`string`, `string`> |
|  `metadata` | [`RunMetadata`](#runmetadata) |
|  `output?` | `Output`<`unknown`, `unknown`, `never`> |

***

### OpenContext

What a driver's `open` receives: the run and the harness environment jigs built.

#### Properties

| Property | Type |
| :------ | :------ |
|  `env` | `Record`<`string`, `string`> |
|  `metadata` | [`RunMetadata`](#runmetadata) |

***

### OpenedModel

A live provider model and what closing it releases.

#### Properties

| Property | Type |
| :------ | :------ |
|  `model` | `LanguageModel` |

#### Methods

##### close()

```ts
close(): Promise<void>;
```

###### Returns

`Promise`<`void`>

## Type Aliases

### CheckResult

```ts
type CheckResult = 
  | {
  detail?: string;
  ok: true;
}
  | {
  ok: false;
  reason: string;
  repair: string;
};
```

A check's outcome: a pass with an optional `detail`, or a failure with its repair.

***

### DecisionGeneration

```ts
type DecisionGeneration<QUESTIONS> = object;
```

What a driver's `decide` returns: one answer per question.

#### Type Parameters

| Type Parameter | Default type |
| :------ | :------ |
| `QUESTIONS` *extends* [`JevQuestions`](jigs.md#jevquestions) | [`JevQuestions`](jigs.md#jevquestions) |

#### Properties

| Property | Type |
| :------ | :------ |
|  `answers` | [`JevAnswers`](jigs.md#jevanswers)<`QUESTIONS`> |

***

### DriverRequest

```ts
type DriverRequest = 
  | AgentRequest
  | ModelRequest
  | AskJevOptions<JevQuestions>
  | HarnessTarget;
```

Any request a driver's checks and environment allowlist are asked about.

***

### ExecutorGeneration

```ts
type ExecutorGeneration = ModelGeneration & object;
```

What a driver's call returns: the reply text, provider metadata and any structured output.

#### Type Declaration

| Name | Type |
| :------ | :------ |
| `output?` | `unknown` |

***

### HarnessTarget

```ts
type HarnessTarget = object;
```

A harness to open in a worktree, resuming a session when one is given.

#### Properties

| Property | Type |
| :------ | :------ |
|  `cwd` | `string` |
|  `harness` | [`Harness`](jigs.md#harness-2) |
|  `resume?` | [`AgentSessionRef`](jigs.md#agentsessionref) |

***

### RunMetadata

```ts
type RunMetadata = Pick<WorkflowMetadata, "workflowRunId">;
```

The run a step belongs to: `getWorkflowMetadata()` inside the step.

***

### RunRequest

```ts
type RunRequest = Extract<AgentRequest, {
  cwd: string;
}>;
```

An agent request that runs in a worktree.

## Functions

### createAgentRunner()

```ts
function createAgentRunner(harness, options): Promise<AgentRunner>;
```

Open a Claude Code or Codex harness inside a factory's own step, the way the built-in agent
step does: the environment allowlist with the factory's `agents.env`, the request and
just-in-time checks, the worktree lock, Codex's private home and app server, and the Claude
spawn hook. The returned `model` is the live provider, ready for `generateText`.

#### Parameters

| Parameter | Type |
| :------ | :------ |
| `harness` | [`Harness`](jigs.md#harness-2) |
| `options` | [`AgentRunnerOptions`](#agentrunneroptions) |

#### Returns

`Promise`<[`AgentRunner`](#agentrunner)>

#### Remarks

Call it inside a `"use step"` function, never in a workflow. The step can hand the provider a
function, such as a tool-approval hook or a logger, because a step runs where functions are
allowed; pass it through the AI SDK call.

It throws `JitCheckError` when a just-in-time check fails, and [AgentSessionError](#agentsessionerror) when
`resume` names a session this harness cannot resume. Pi has no provider model, so a Pi
descriptor throws: run Pi with `runAgent`.

#### Example

```ts
import type { AgentSessionRef, Harness } from "@jigs-ai/jigs";
import { createAgentRunner } from "@jigs-ai/jigs/steps";
import { generateText } from "ai";
import { getWorkflowMetadata } from "workflow";

export async function runWithTemperature(request: {
  harness: Harness;
  cwd: string;
  prompt: string;
  resume?: AgentSessionRef | undefined;
}) {
  "use step";
  const runner = await createAgentRunner(request.harness, {
    cwd: request.cwd,
    run: getWorkflowMetadata(),
    resume: request.resume,
  });
  try {
    const result = await generateText({ model: runner.model, prompt: request.prompt, temperature: 0 });
    return { text: result.text, session: runner.sessionFrom(result) };
  } finally {
    await runner.close();
  }
}
```
