jigs
Factory and workflow definitions, harness and model descriptors, types and pure helpers.
Durable steps and routines come from the factory-generated #jigs/steps and #jigs/routines.
Example
import { defineWorkflow, harnesses } from "@jigs-ai/jigs";
import { runAgent } from "#jigs/routines";Factory and workflows
EventTrigger
A trigger that starts one run per occurrence its source reports, at most once per occurrence. Each run gets the reference the source hands it, merged over the fixed inputs.
Remarks
A new trigger starts from the moment the service first runs it, with no backfill. After the service was down, it starts runs only for occurrences within lookbackMinutes and records older ones as skipped.
Properties
| Property | Type | Description |
|---|---|---|
active | boolean | An inactive trigger is not armed: its source's occurrences start no runs. |
inputs? | Record<string, unknown> | - |
lookbackMinutes? | number | How far back to catch up after the service was down. Defaults to 60. |
maxActive? | number | Runs of this trigger active at once. Defaults to 20; further occurrences wait, oldest first. |
source | SourceDescriptor | - |
workflow | string | - |
Factory
What a factory repo hands the service: its workflows, keyed by name, and the schedules and event triggers that start them. A schedule is keyed by its own name rather than nested under a workflow. The name is what runs, status and jigs doctor refer to, and one workflow can carry several.
Properties
| Property | Type |
|---|---|
schedules? | Record<string, Schedule> |
triggers? | Record<string, EventTrigger> |
workflows | Record<string, AnyWorkflowDefinition> |
LinearDelegationInputs
The inputs a linear.delegations source hands each run it starts.
Extended by
Properties
LinearMentionInputs
The inputs a linear.mentions source hands each run it starts.
Extends
Properties
Schedule
One recurring trigger: a workflow, when to fire it, and the inputs to fire it with. *
Properties
| Property | Type | Description |
|---|---|---|
active | boolean | An inactive schedule never fires. |
cron | string | Five fields, evaluated in the service host's local time zone. |
inputs | Record<string, unknown> | - |
workflow | string | - |
SourceDescriptor
What an event trigger watches: a source kind and the provider's own query parameters for it. Plain data, so it can sit in jigs.config.ts; a source's constructor builds it.
Properties
| Property | Type |
|---|---|
kind | string |
params | Record<string, unknown> |
WorkflowDefinition
A workflow: its function, its input schema, and what a run needs before it may start.
Type Parameters
| Type Parameter | Default type |
|---|---|
S extends z.ZodType | z.ZodType |
Properties
AgentsDefinition
type AgentsDefinition = z.input<typeof agentsSchema>;Settings for the agent harnesses this factory runs.
BindingDefinition
type BindingDefinition = z.input<typeof bindingSchema>;A repository this factory works in: its remote, the GitHub installation that reaches it, and how a worktree cut from it is provisioned.
Remarks
installationName is the name an admin gave the GitHub App installation on the hub. Pushes, pull requests and their events go through it.
Example
Use this value for bindings.api in jigs.config.ts.
import type { BindingDefinition } from "@jigs-ai/jigs";
const api = {
remote: "git@github.com:acme/api.git",
installationName: "github-acme",
postCreate: ["pnpm install"],
} satisfies BindingDefinition;FactoryDefinition
type FactoryDefinition = z.input<typeof factoryConfigSchema> & object;Operating settings and deferred workflow modules declared by a factory.
Type Declaration
| Name | Type |
|---|---|
workflows | Record<string, WorkflowImport> |
GitHubDefinition
type GitHubDefinition = z.input<typeof githubSchema>;Who the operator is on GitHub.
Remarks
jigs acts on GitHub as the GitHub App the hub assigns this factory, so its pull requests come from <app-slug>[bot] and the operator approves them with a review.
Example
Use this value for github in jigs.config.ts.
import type { GitHubDefinition } from "@jigs-ai/jigs";
const github = {
operator: "octocat",
coAuthor: "Octo Cat <octocat@example.com>",
} satisfies GitHubDefinition;GitHubIssueInputs
type GitHubIssueInputs = RepositoryRef & object;The inputs a github.issues source hands each run it starts.
Type Declaration
| Name | Type | Description |
|---|---|---|
number | number | The repository-local issue number. |
GitHubIssuesParams
type GitHubIssuesParams = z.input<typeof gitHubIssuesParamsSchema>;Which issues a github.issues source starts runs for. Each list matches any of its values; leaving one out does not filter on it.
installationName: the GitHub App installation, as named on the hub, whose repositories it watches.repositories:owner/reponames, such asacme/api, in any case.authors: GitHub logins of who opened the issue.labels: label names; an issue with any of them matches.
GitHubPullRequestsParams
type GitHubPullRequestsParams = z.input<typeof gitHubPullRequestsParamsSchema>;Which pull requests a github.pullRequests source starts runs for. Each list matches any of its values; leaving one out does not filter on it.
installationName: the GitHub App installation, as named on the hub, whose repositories it watches.repositories:owner/reponames, such asacme/api, in any case.authors: GitHub logins of who opened the pull request, such asdependabot[bot].labels: label names; a pull request with any of them matches.baseBranches: the branches the pull request merges into, such asmain.
GitHubPushesParams
type GitHubPushesParams = z.input<typeof gitHubPushesParamsSchema>;Which pushes a github.pushes source starts runs for. Each list matches any of its values; leaving one out does not filter on it.
installationName: the GitHub App installation, as named on the hub, whose repositories it watches.repositories:owner/reponames, such asacme/api, in any case.branches: branch names, such asmain.
GitHubPushInputs
type GitHubPushInputs = RepositoryRef & object;The inputs a github.pushes source hands each run it starts.
Type Declaration
| Name | Type | Description |
|---|---|---|
after | string | The commit the branch points at after the push. |
before | string | The commit the branch pointed at before the push, all zeros for a new branch. |
branch | string | The branch pushed to, such as main. |
GitHubReleaseInputs
type GitHubReleaseInputs = RepositoryRef & object;The inputs a github.releases source hands each run it starts.
Type Declaration
| Name | Type | Description |
|---|---|---|
tag | string | The release's tag, such as v1.2.0. |
GitHubReleasesParams
type GitHubReleasesParams = z.input<typeof gitHubReleasesParamsSchema>;Which releases a github.releases source starts runs for.
installationName: the GitHub App installation, as named on the hub, whose repositories it watches.repositories:owner/reponames, such asacme/api, in any case; leaving it out watches them all.
LinearAgentSessionsParams
type LinearAgentSessionsParams = z.input<typeof linearAgentSessionsParamsSchema>;Which Linear agent sessions a linear.delegations or linear.mentions source starts runs for. Each list matches any of its values; leaving one out does not filter on it.
installationName: the Linear installation, as named on the hub, whose sessions it watches.teams: team keys, such asENG, or team ids.projects: project ids, or the id at the end of a project's URL.labels: label names, as Linear shows them.creators: emails of the people who delegated the issue or mentioned the app, in any case.
LinearDefinition
type LinearDefinition = z.input<typeof linearSchema>;Who a ticket run's Linear questions and notes mention.
Remarks
operator is the email of the Linear user who runs the factory. With it, every question and note a ticket run posts mentions the operator and the ticket's assignee; without it, the ticket's creator and assignee. jigs doctor fails when no Linear user has the email. Steps read it from the built factory, so a change takes effect after a rebuild, which jigs up does.
Example
Use this value for linear in jigs.config.ts.
import type { LinearDefinition } from "@jigs-ai/jigs";
const linear = {
operator: "salim@example.com",
} satisfies LinearDefinition;PagerDutyIncidentsParams
type PagerDutyIncidentsParams = z.input<typeof pagerDutyIncidentsParamsSchema>;Which incidents a pagerduty.incidents source starts runs for. Each list matches any of its values; leaving one out does not filter on it.
installationName: the PagerDuty installation, as named on the hub, whose incidents it watches.services: PagerDuty service IDs, such asP48FPG2.teams: PagerDuty team IDs.urgencies:high,lowor both.
TicketWorkflowInputs
type TicketWorkflowInputs<S> = WorkflowInputs<S>;Ticket references are ordinary inputs; resolve them explicitly in a step.
Type Parameters
| Type Parameter |
|---|
S extends z.ZodType<{ ticket: string; }> |
WorkflowInputs
type WorkflowInputs<S> = z.output<S> & Injected;Parsed workflow inputs with the trigger that started the run.
Type Parameters
| Type Parameter |
|---|
S extends z.ZodType |
github
const github: object;Event-trigger sources on GitHub.
Type Declaration
| Name | Type | Description |
|---|---|---|
issues() | (params) => SourceDescriptor | Start a run for each issue, with GitHubIssueInputs as its inputs. An issue starts at most one run, ever: the first time any of its events shows it open and matching the filters, such as when it is opened or labeled. An issue reopened after its run ended starts no new one; rerun it with jigs run. Remarks The GitHub App must subscribe to the Issues event. Events the factory's own GitHub App caused start no run, so an issue the App opens starts one only once a person acts on it, such as by adding a label the trigger filters on. Example import { github } from "@jigs-ai/jigs"; const source = github.issues({ installationName: "github-acme", repositories: ["acme/api"], labels: ["agent"], }); |
pullRequests() | (params) => SourceDescriptor | Start a run for each pull request, with its PullRequestRef as the inputs. A pull request starts at most one run, ever: the first time any of its events shows it open, not a draft and matching the filters, such as when it is opened, labeled or marked ready for review. A pull request reopened after its run ended starts no new one; rerun it with jigs run. Remarks Events the factory's own GitHub App caused start no run, so a pull request the App opens starts one only once a person acts on it, such as by adding a label the trigger filters on. Example import { github } from "@jigs-ai/jigs"; const source = github.pullRequests({ installationName: "github-acme", repositories: ["acme/api"], authors: ["dependabot[bot]"], }); |
pushes() | (params) => SourceDescriptor | Start a run for each push to a branch, with GitHubPushInputs as its inputs. Each push starts at most one run, ever. Tag pushes and branch deletions start none. A push the factory's own GitHub App made, such as merging a person's pull request, starts runs like any other. Remarks The GitHub App must subscribe to the Push event. Example import { github } from "@jigs-ai/jigs"; const source = github.pushes({ installationName: "github-acme", repositories: ["acme/api"], branches: ["main"], }); |
releases() | (params) => SourceDescriptor | Start a run for each published release, with GitHubReleaseInputs as its inputs. A release starts at most one run, ever, once it is published and not a prerelease: a prerelease starts its run when it becomes a release. Drafts start none. Remarks The GitHub App must subscribe to the Release event and needs Contents: read. Example import { github } from "@jigs-ai/jigs"; const source = github.releases({ installationName: "github-acme", repositories: ["acme/api"], }); |
installationNameSchema
const installationNameSchema: ZodString;An installation's name, as an admin set it on the hub: lowercase letters, digits and hyphens, starting with a letter. Use it for a workflow input that names an installation.
linear
const linear: object;Event-trigger sources on Linear.
Type Declaration
| Name | Type | Description |
|---|---|---|
delegations() | (params) => SourceDescriptor | Start a run whenever someone delegates an issue to the factory's Linear app, with LinearDelegationInputs as its inputs. Example import { linear } from "@jigs-ai/jigs"; const source = linear.delegations({ installationName: "acme", teams: ["ENG"] }); |
mentions() | (params) => SourceDescriptor | Start a run whenever someone mentions the factory's Linear app in a comment on an issue, with LinearMentionInputs as its inputs. Example import { linear } from "@jigs-ai/jigs"; const source = linear.mentions({ installationName: "acme", labels: ["agent"] }); |
Remarks
Delegating an issue to the factory's Linear app, or mentioning the app in a comment, opens a Linear agent session. Each session starts at most one run per trigger, ever. The hub posts the session's first reply, so Linear shows the app at work while the run starts. That reply appears even when no trigger matches, so make the filters match what the app is for. Every factory assigned the app hears every session, and each matching trigger starts its own run. Sessions not on an issue, and sessions the app opened itself, start no run.
pagerduty
const pagerduty: object;Event-trigger sources on PagerDuty.
Type Declaration
| Name | Type | Description |
|---|---|---|
incidents() | (params) => SourceDescriptor | Watch for new incidents. Every new incident starts at most one run, ever, with { installationName, incident: "<id>" } as its inputs, even one acknowledged or resolved before the service saw it; the workflow can check the status and skip one that is already handled. The run starts as soon as the hub passes on PagerDuty's incident.triggered event. Example import { pagerduty } from "@jigs-ai/jigs"; const source = pagerduty.incidents({ installationName: "acme", services: ["P48FPG2"], urgencies: ["high"], }); |
slack
const slack: object;Event-trigger sources for Slack, one per trigger in jigs.config.ts.
Type Declaration
| Name | Type | Description |
|---|---|---|
mentions() | (__namedParameters) => SourceDescriptor | Only the top-level messages that mention the factory's bot. |
messages() | (__namedParameters) => SourceDescriptor | Every top-level message in the channels. |
Remarks
Both read top-level messages in the listed channels of one Slack installation, named as on the hub, whose bot must be a member of them, and start one run per message with the inputs { installationName, channel, ts }. Posts from people, other bots and apps count, including posts with files. The factory's own posts never count, and neither do thread replies, edits, deletes, joins or other channel events. Direct messages are never read. Channels are listed by ID, such as C0123ABCD, not by name.
Example
Start a run for every message that mentions the bot in one channel.
import { slack } from "@jigs-ai/jigs";
const triggers = {
"answer-questions": {
active: process.env.ANSWER_QUESTIONS_ACTIVE === "true",
workflow: "answer",
source: slack.mentions({ installationName: "acme", channels: ["C0123ABCD"] }),
},
};ticketInputSchema
const ticketInputSchema: ZodUnion<readonly [ZodUUID, ZodString]>;Accept a Linear issue UUID or an uppercase team-and-number ticket identifier.
defineFactory()
function defineFactory<T>(factory): T;Check the declaration against what jigs accepts and preserve its inferred keys, without loading its workflows.
Type Parameters
| Type Parameter |
|---|
T extends FactoryDefinition |
Parameters
| Parameter | Type |
|---|---|
factory | T & Record<Exclude<keyof T, | "github" | "linear" | "hub" | "release" | "bindings" | "agents" | "workflows" | "schedules" | "triggers">, never> |
Returns
T
defineWorkflow()
function defineWorkflow<S>(definition): WorkflowDefinition<S>;Declare a workflow as the default export of its file. It returns the definition unchanged; it exists so TypeScript checks the workflow's parameter against the input schema.
Type Parameters
| Type Parameter |
|---|
S extends ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>> |
Parameters
| Parameter | Type |
|---|---|
definition | WorkflowDefinition<S> |
Returns
Example
import { defineWorkflow, type WorkflowInputs } from "@jigs-ai/jigs";
import { z } from "zod";
const inputs = z.object({ name: z.string() });
export async function hello(input: WorkflowInputs<typeof inputs>) {
"use workflow";
return `Hello, ${input.name}!`;
}
export default defineWorkflow({ inputs, workflow: hello });Harnesses and models
AgentInstallation
type AgentInstallation = object;Names the installation, as an admin named it on the hub, an agent acts through.
Remarks
On github, the agent gets a fresh token of that GitHub App installation in GH_TOKEN, so gh works as the App's bot, and git reaches the installation account's repositories over HTTPS with that token. Its commits are authored by the bot, while your own git configuration stays the committer and signer. On linear, the workspace's token goes in JIGS_LINEAR_TOKEN; on pagerduty, the account's token goes in JIGS_PAGERDUTY_TOKEN.
Example
import { harnesses } from "@jigs-ai/jigs";
const builder = harnesses.codex({
model: "gpt-5.6-sol",
github: { installationName: "github-acme" },
});Properties
| Property | Type |
|---|---|
installationName | string |
AskableHarness
type AskableHarness =
| ClaudeHarness & ToolFree
| PiHarness & ToolFree;A harness askAgent can run with no tools: Claude Code or Pi, without MCP servers, provider access or a Pi tool allowlist. Codex has no mode without tools.
AskableModelSource
type AskableModelSource = Exclude<ModelSource, OpenaiCodexSource>;A model source accepted by a direct model call.
ClaudeHarness
type ClaudeHarness = JsonOnly<Omit<ClaudeAgentOptions, ClaudePolicyKey>> & HarnessSkills & object;A Claude Code harness descriptor: the Claude Agent SDK's own options that are data, minus each ClaudePolicyKey, plus the model, jigs' MCP server shape and HarnessSkills.
Type Declaration
| Name | Type | Description |
|---|---|---|
github? | AgentInstallation | Acts on GitHub as the factory's App, through this installation. |
kind | "claude" | - |
linear? | AgentInstallation | Acts on Linear as the factory's app, through this installation. |
mcpServers? | Record<string, McpServerConfig> | - |
model | string | - |
pagerduty? | AgentInstallation | Acts on PagerDuty as the factory's app, through this installation. |
ClaudeHarnessSettings
type ClaudeHarnessSettings = Omit<ClaudeHarness, "kind">;The one argument harnesses.claude takes: the model and any Claude Code settings.
ClaudePolicyKey
type ClaudePolicyKey = typeof claudePolicyKeys[number];A Claude Code option a descriptor cannot name, because jigs sets it itself or holds it as policy.
Remarks
jigs sets the working directory, environment, executable, session and output format for every step, and holds permissions, setting sources and MCP servers as policy. extraArgs would rewrite any of those. agents, settings, plugins and projectConfigRoot would bring in unprobed MCP servers, environment, permissions and hooks from outside the worktree; they come from the repository's project settings instead. jigs fills plugins itself to load the descriptor's skills, which replace Claude Code's own skills option.
CodexHarness
type CodexHarness = JsonOnly<Omit<CodexAppServerSettings, CodexPolicyKey>> & HarnessSkills & object;A Codex harness descriptor: the provider's own settings that are data, minus each CodexPolicyKey, plus the model, jigs' MCP server shape and HarnessSkills.
Type Declaration
| Name | Type | Description |
|---|---|---|
github? | AgentInstallation | Acts on GitHub as the factory's App, through this installation. |
kind | "codex" | - |
linear? | AgentInstallation | Acts on Linear as the factory's app, through this installation. |
mcpServers? | Record<string, McpServerConfig> | - |
model | string | - |
pagerduty? | AgentInstallation | Acts on PagerDuty as the factory's app, through this installation. |
CodexHarnessSettings
type CodexHarnessSettings = Omit<CodexHarness, "kind">;The one argument harnesses.codex takes: the model and any Codex settings.
CodexPolicyKey
type CodexPolicyKey = typeof codexPolicyKeys[number];A Codex setting a descriptor cannot name, because jigs sets it itself or holds it as policy.
Remarks
jigs sets the working directory, environment, executable, thread and session for every step, and holds the approval and sandbox policies and MCP servers. configOverrides would rewrite the sandbox and MCP tables.
GithubMcpOptions
type GithubMcpOptions = object;Options for githubMcp on a Pi harness.
Properties
| Property | Type | Description |
|---|---|---|
tools | string[] | Raw MCP tool names the model may call. jigs adds the probe tool, search_repositories. |
Harness
type Harness =
| ClaudeHarness
| CodexHarness
| PiHarness;A serializable agent-program descriptor.
HarnessForOptions
type HarnessForOptions<H, O> = [Extract<keyof O, keyof ToolFree>] extends [never] ? H & ToolFree : H;The descriptor a harness constructor returns for its options. It is also ToolFree, so askAgent accepts it, when the options name no tools, MCP servers or provider access.
Type Parameters
| Type Parameter |
|---|
H |
O |
HarnessKind
type HarnessKind = Harness["kind"];The stable name of an agent harness.
HarnessSkills
type HarnessSkills = object;Skill folders an agent loads, each holding a SKILL.md and any files it refers to.
Remarks
Each path is relative to the factory root, or absolute. jigs copies every folder into a private place for each agent call, so the skills reach the agent whatever its working directory and nothing the agent changes there reaches the factory. Each folder is copied under its own name, so two folders cannot share one; keep it the same as the name in its SKILL.md. A run whose folder is missing or has no SKILL.md fails its checks before the agent starts. Skills apply when an agent runs in a directory, not to askAgent.
Properties
| Property | Type |
|---|---|
skills? | string[] |
JsonOnly
type JsonOnly<T> = { [K in keyof T as false extends IsData<Exclude<T[K], undefined>> ? never : K]: T[K] };The keys of a settings type whose values are data, so they can cross into a step.
Type Parameters
| Type Parameter |
|---|
T |
LinearMcpOptions
type LinearMcpOptions = object;Options for linearMcp on a Pi harness.
Properties
| Property | Type | Description |
|---|---|---|
tools | string[] | Raw MCP tool names the model may call. jigs adds the probe tool, list_teams. |
McpHttpServerConfig
type McpHttpServerConfig = object;Configuration for an MCP server reached over HTTP.
Remarks
Credentials never appear in workflow code: each headers value and bearerTokenEnv name an environment variable of the service, read when the step starts the agent. A step whose named variable is not set fails before the agent starts.
Properties
| Property | Type | Description |
|---|---|---|
bearerTokenEnv? | string | Names the service variable holding a token sent as Authorization: Bearer <token>. |
disabledTools? | string[] | Raw MCP tool names the model may not call. Pi takes its tools allowlist instead. |
headers? | Record<string, string> | Maps HTTP header names to the names of the service variables holding their values. |
probe | McpToolProbe | - |
url | string | - |
McpServerConfig
type McpServerConfig =
| McpStdioServerConfig
| McpHttpServerConfig;An MCP server an agent harness can expose to the model.
McpStdioServerConfig
type McpStdioServerConfig = object;Configuration for an MCP server launched as a child process.
Remarks
Credentials never appear in workflow code: each env value names an environment variable of the service, read when the step starts the agent. A step whose named variable is not set fails before the agent starts.
Example
import { harnesses } from "@jigs-ai/jigs";
// The server reads BRAVE_API_KEY; its value comes from the service's SEARCH_API_KEY.
const researcher = harnesses.claude({
model: "opus",
mcpServers: {
search: {
command: "npx",
args: ["-y", "@brave/brave-search-mcp-server"],
env: { BRAVE_API_KEY: "SEARCH_API_KEY" },
probe: { tool: "brave_web_search", arguments: { query: "jigs", count: 1 } },
},
},
});Properties
| Property | Type | Description |
|---|---|---|
args? | string[] | - |
command | string | - |
disabledTools? | string[] | Raw MCP tool names the model may not call. Pi takes its tools allowlist instead. |
env? | Record<string, string> | Maps the server's variable names to the names of the service variables holding their values. |
probe | McpToolProbe | - |
McpToolProbe
type McpToolProbe = object;A harmless MCP tool call used to prove that a configured server is available.
Properties
| Property | Type |
|---|---|
arguments? | Record<string, unknown> |
tool | string |
ModelKind
type ModelKind = ModelSource["kind"];The stable name of a model source.
ModelSource
type ModelSource =
| OpenrouterSource
| OpenaiCompatibleSource
| OpenaiCodexSource;Any configured source from which a model can answer.
OpenaiCodexSource
type OpenaiCodexSource = object;The Codex subscription model source used only by the Pi harness.
Properties
| Property | Type |
|---|---|
kind | "openai-codex" |
model | string |
OpenaiCompatibleSource
type OpenaiCompatibleSource = object;An OpenAI-compatible API model source.
Properties
| Property | Type |
|---|---|
apiKeyEnv? | string |
baseUrl | string |
kind | "openai-compatible" |
model | string |
name | string |
OpenrouterSource
type OpenrouterSource = object;An OpenRouter API model source.
Properties
| Property | Type |
|---|---|
apiKeyEnv | string |
kind | "openrouter" |
model | string |
PagerdutyMcpOptions
type PagerdutyMcpOptions = object;Options for pagerdutyMcp on a Pi harness.
Properties
| Property | Type | Description |
|---|---|---|
tools | string[] | Raw MCP tool names the model may call. jigs adds the probe tool, list_incidents. |
PiHarness
type PiHarness =
| PiOpenaiCompatibleHarness
| PiOtherHarness;A Pi harness descriptor backed by a nested model source.
PiHarnessOptions
type PiHarnessOptions = Pick<PiHarness,
| "thinking"
| "tools"
| "mcpServers"
| "github"
| "linear"
| "pagerduty"
| "skills"> & object;Options for harnesses.pi. compat applies only to an OpenAI-compatible model source.
Type Declaration
| Name | Type |
|---|---|
compat? | Partial<PiOpenaiCompatibleOptions> |
PiMcpHttpServerConfig
type PiMcpHttpServerConfig = Omit<McpHttpServerConfig, "bearerTokenEnv" | "disabledTools"> & object &
| {
auth: "oauth";
bearerTokenEnv?: never;
}
| {
auth?: false;
bearerTokenEnv?: never;
}
| {
auth?: never;
bearerTokenEnv: string;
};An HTTP MCP server Pi exposes through an explicit direct-tool allowlist.
Type Declaration
| Name | Type | Description |
|---|---|---|
tools | string[] | Raw MCP tool names the model may call. This must include the probe tool. |
PiMcpServerConfig
type PiMcpServerConfig =
| PiMcpStdioServerConfig
| PiMcpHttpServerConfig;An explicitly configured MCP server accepted by the Pi harness.
PiMcpStdioServerConfig
type PiMcpStdioServerConfig = Omit<McpStdioServerConfig, "disabledTools"> & object;A stdio MCP server Pi exposes through an explicit direct-tool allowlist.
Type Declaration
| Name | Type | Description |
|---|---|---|
tools | string[] | Raw MCP tool names the model may call. This must include the probe tool. |
PiOpenaiCompatibleHarness
type PiOpenaiCompatibleHarness = SharedPiHarness & object;A Pi harness descriptor backed by an OpenAI-compatible source, with its compatibility hints.
Type Declaration
| Name | Type |
|---|---|
compat | PiOpenaiCompatibleOptions |
model | OpenaiCompatibleSource |
PiOpenaiCompatibleOptions
type PiOpenaiCompatibleOptions = object;Pi-specific compatibility hints for an OpenAI-compatible model.
Properties
| Property | Type |
|---|---|
supportsDeveloperRole | boolean |
supportsReasoningEffort | boolean |
PiOtherHarness
type PiOtherHarness = SharedPiHarness & object;A Pi harness descriptor backed by any source other than an OpenAI-compatible one.
Type Declaration
| Name | Type |
|---|---|
compat? | never |
model | Exclude<ModelSource, OpenaiCompatibleSource> |
ToolFree
type ToolFree = object;Marks a descriptor that names no tools, MCP servers or provider access.
Properties
| Property | Type |
|---|---|
github? | never |
linear? | never |
mcpServers? | never |
pagerduty? | never |
tools? | never |
harnesses
const harnesses: object;Constructors for agent-harness descriptors.
Type Declaration
| Name | Type | Default value |
|---|---|---|
claude() | <O>(settings) => HarnessForOptions<ClaudeHarness, O> | claudeHarness |
codex() | <O>(settings) => CodexHarness | codexHarness |
pi() | { <O> (model, options?): HarnessForOptions<PiOpenaiCompatibleHarness, O>; <O> (model, options?): HarnessForOptions<PiOtherHarness, O>; <M, O> (model, options?): HarnessForOptions<PiHarness, O>; } | piHarness |
harnessKinds
const harnessKinds: ["claude" | "codex" | "pi", ...("claude" | "codex" | "pi")[]];Every harness kind this release of jigs can build, taken from the keys of harnesses. Use it for a workflow input that names a harness, so a new kind appears without editing the input.
Example
import { harnessKinds } from "@jigs-ai/jigs";
import { z } from "zod";
const inputs = z.object({ harness: z.enum(harnessKinds) });models
const models: object;Constructors for model-source descriptors.
Type Declaration
| Name | Type | Description |
|---|---|---|
openaiCodex() | (model) => OpenaiCodexSource | Build a source that runs through the Codex subscription Pi is logged in to. Only harnesses.pi accepts it. |
openaiCompatible() | (options) => OpenaiCompatibleSource | Build a source for an OpenAI-compatible server. |
openrouter() | (model, options) => OpenrouterSource | Build an OpenRouter source. Its key is read from OPENROUTER_API_KEY unless apiKeyEnv names another variable. |
githubMcp()
Call Signature
function githubMcp(): McpStdioServerConfig;An MCP server that gives an agent GitHub's own tools, acting as the factory's GitHub App.
Returns
Remarks
It runs github-mcp-server, which must be installed on the machine, with the token of an agent whose harness sets github; a harness without github cannot use it. Tools that need a user, such as get_me, are left out, since an App's token cannot answer them. Pi needs the list of tools the model may call.
Example
import { githubMcp, harnesses } from "@jigs-ai/jigs";
const builder = harnesses.claude({
model: "opus",
github: { installationName: "github-acme" },
mcpServers: { github: githubMcp() },
});Call Signature
function githubMcp(options): PiMcpStdioServerConfig;An MCP server that gives an agent GitHub's own tools, acting as the factory's GitHub App.
Parameters
| Parameter | Type |
|---|---|
options | GithubMcpOptions |
Returns
Remarks
It runs github-mcp-server, which must be installed on the machine, with the token of an agent whose harness sets github; a harness without github cannot use it. Tools that need a user, such as get_me, are left out, since an App's token cannot answer them. Pi needs the list of tools the model may call.
Example
import { githubMcp, harnesses } from "@jigs-ai/jigs";
const builder = harnesses.claude({
model: "opus",
github: { installationName: "github-acme" },
mcpServers: { github: githubMcp() },
});linearMcp()
Call Signature
function linearMcp(): McpHttpServerConfig;An MCP server that gives an agent Linear's own tools, acting as the factory on Linear.
Returns
Remarks
It reaches Linear's hosted server at https://mcp.linear.app/mcp with the token of an agent whose harness sets linear; a harness without linear cannot use it. In app mode the agent acts as the factory's Linear app, in key mode as the API key's user. Pi needs the list of tools the model may call. The result is plain data, so spread it to change a field, such as url to https://mcp.linear.app/mcp/readonly for read tools only.
Example
import { harnesses, linearMcp } from "@jigs-ai/jigs";
const triager = harnesses.claude({
model: "opus",
linear: { installationName: "linear-acme" },
mcpServers: { linear: linearMcp() },
});Call Signature
function linearMcp(options): PiMcpHttpServerConfig;An MCP server that gives an agent Linear's own tools, acting as the factory on Linear.
Parameters
| Parameter | Type |
|---|---|
options | LinearMcpOptions |
Returns
Remarks
It reaches Linear's hosted server at https://mcp.linear.app/mcp with the token of an agent whose harness sets linear; a harness without linear cannot use it. In app mode the agent acts as the factory's Linear app, in key mode as the API key's user. Pi needs the list of tools the model may call. The result is plain data, so spread it to change a field, such as url to https://mcp.linear.app/mcp/readonly for read tools only.
Example
import { harnesses, linearMcp } from "@jigs-ai/jigs";
const triager = harnesses.claude({
model: "opus",
linear: { installationName: "linear-acme" },
mcpServers: { linear: linearMcp() },
});pagerdutyMcp()
Call Signature
function pagerdutyMcp(): McpHttpServerConfig;An MCP server that gives an agent PagerDuty's own tools, acting as the factory's PagerDuty app.
Returns
Remarks
It reaches PagerDuty's hosted server with the token of an agent whose harness sets pagerduty; a harness without pagerduty cannot use it. The token carries the scopes jigs itself uses, so the agent can read and update incidents and read users; other tools fail for lack of a scope. The token belongs to an app, not a user, so get_user_data is disabled and list_incidents cannot filter by the assigned or teams request scope. Pi needs the list of tools the model may call; leave get_user_data out of it. The result is plain data: for an account in the EU service region, spread it with url: "https://mcp.eu.pagerduty.com/mcp".
Example
import { harnesses, pagerdutyMcp } from "@jigs-ai/jigs";
const triager = harnesses.claude({
model: "opus",
pagerduty: { installationName: "pagerduty-acme" },
mcpServers: { pagerduty: pagerdutyMcp() },
});Call Signature
function pagerdutyMcp(options): PiMcpHttpServerConfig;An MCP server that gives an agent PagerDuty's own tools, acting as the factory's PagerDuty app.
Parameters
| Parameter | Type |
|---|---|
options | PagerdutyMcpOptions |
Returns
Remarks
It reaches PagerDuty's hosted server with the token of an agent whose harness sets pagerduty; a harness without pagerduty cannot use it. The token carries the scopes jigs itself uses, so the agent can read and update incidents and read users; other tools fail for lack of a scope. The token belongs to an app, not a user, so get_user_data is disabled and list_incidents cannot filter by the assigned or teams request scope. Pi needs the list of tools the model may call; leave get_user_data out of it. The result is plain data: for an account in the EU service region, spread it with url: "https://mcp.eu.pagerduty.com/mcp".
Example
import { harnesses, pagerdutyMcp } from "@jigs-ai/jigs";
const triager = harnesses.claude({
model: "opus",
pagerduty: { installationName: "pagerduty-acme" },
mcpServers: { pagerduty: pagerdutyMcp() },
});Agent and model requests/results
AgentResult
type AgentResult<T> = ModelResult<T> & object;A model result with the session reference an agent harness returned, when it returned one.
Type Declaration
| Name | Type |
|---|---|
session? | AgentSessionRef |
Type Parameters
| Type Parameter | Default type |
|---|---|
T | unknown |
AgentSessionRef
type AgentSessionRef = object;A session reference: the small piece of data that lets a later runAgent call resume the same harness session. Pass it back as resume.
Properties
| Property | Type | Description |
|---|---|---|
descriptor | string | The harness descriptor the session was recorded on, as describeHarness renders it. |
harness | Harness["kind"] | - |
id | string | - |
AskAgentOptions
type AskAgentOptions<T> = object;Options for one harness turn without tools or a worktree.
Type Parameters
| Type Parameter | Default type |
|---|---|
T | undefined |
Properties
| Property | Type |
|---|---|
harness | AskableHarness |
output? | z.ZodType<T> |
prompt | string |
system? | string |
AskModelOptions
type AskModelOptions<T> = object;Options for one API model call.
Type Parameters
| Type Parameter | Default type |
|---|---|
T | undefined |
Properties
| Property | Type |
|---|---|
model | AskableModelSource |
output? | z.ZodType<T> |
prompt | string |
system? | string |
ModelResult
type ModelResult<T> = object;Text and structured output returned by a model call.
Type Parameters
| Type Parameter | Default type |
|---|---|
T | unknown |
Properties
| Property | Type |
|---|---|
output | T |
text | string |
OutputJsonSchema
type OutputJsonSchema = Record<string, unknown>;The serializable JSON Schema sent across the workflow-step boundary.
RunAgentOptions
type RunAgentOptions<T> = object;Options for an agent that works inside a directory.
Type Parameters
| Type Parameter | Default type |
|---|---|
T | undefined |
Properties
| Property | Type | Description |
|---|---|---|
cwd | string | - |
harness | Harness | - |
output? | z.ZodType<T> | - |
prompt | string | - |
resume? | AgentSessionRef | The session reference of an earlier run to continue. |
describeHarness()
function describeHarness(harness): string;A harness descriptor as a string that ignores field order: two descriptors that list the same settings in another order render the same.
Parameters
| Parameter | Type |
|---|---|
harness | Harness |
Returns
string
unwrapAgentStep()
function unwrapAgentStep(result): AgentResult;Convert returned execution failure markers into errors the workflow throws.
Parameters
| Parameter | Type |
|---|---|
result | | AgentResult | { jitFailure: object & object[]; } | { resumeFailed: string; } |
Returns
Decision models
AskJevOptions
type AskJevOptions<QUESTIONS> = object;A decision request in workflow and durable wire form.
Type Parameters
| Type Parameter |
|---|
QUESTIONS extends JevQuestions |
Properties
| Property | Type |
|---|---|
model | OpenrouterSource |
questions | QUESTIONS |
state | JevState |
ChoiceQuestion
type ChoiceQuestion<OPTIONS> = object;A question answered with one named option.
Type Parameters
| Type Parameter | Default type |
|---|---|
OPTIONS extends Record<string, string> | Record<string, string> |
Properties
| Property | Type |
|---|---|
instructions | string |
options | OPTIONS |
type | "choice" |
JevAnswer
type JevAnswer<QUESTION> = QUESTION extends ChoiceQuestion<infer OPTIONS> ? object : QUESTION extends ScoreQuestion ? object : object;The calibrated answer shape selected by one question descriptor.
Type Parameters
| Type Parameter |
|---|
QUESTION extends JevQuestion |
JevAnswers
type JevAnswers<QUESTIONS> = { [KEY in keyof QUESTIONS]: JevAnswer<QUESTIONS[KEY]> };Answers narrowed independently for every named question.
Type Parameters
| Type Parameter |
|---|
QUESTIONS extends JevQuestions |
JevQuestion
type JevQuestion =
| YesNoQuestion
| ChoiceQuestion
| ScoreQuestion;Any question accepted by askJev.
JevQuestions
type JevQuestions = Record<string, JevQuestion>;Named decision questions evaluated against one shared state.
JevResult
type JevResult<QUESTIONS> = object;A typed decision result.
Type Parameters
| Type Parameter |
|---|
QUESTIONS extends JevQuestions |
Properties
| Property | Type |
|---|---|
answers | JevAnswers<QUESTIONS> |
JevState
type JevState = string | JevJsonObject | JevJsonValue[];JSON-compatible evidence evaluated by a decision model.
ScoreQuestion
type ScoreQuestion = object;A question scored over ordered levels, from lowest to highest.
Properties
| Property | Type |
|---|---|
instructions | string |
levels | string[] |
type | "score" |
YesNoQuestion
type YesNoQuestion = object;A calibrated yes-or-no question.
Properties
| Property | Type |
|---|---|
instructions | string |
type | "yes-no" |
choice()
function choice<OPTIONS>(instructions, options): ChoiceQuestion<OPTIONS>;Build a question answered with one named option. It throws unless every option has a description.
Type Parameters
| Type Parameter |
|---|
OPTIONS extends Record<string, string> |
Parameters
| Parameter | Type |
|---|---|
instructions | string |
options | OPTIONS |
Returns
ChoiceQuestion<OPTIONS>
score()
function score(instructions, levels): ScoreQuestion;Build a question scored over ordered levels, from lowest to highest. It throws unless there are at least two levels, each described.
Parameters
| Parameter | Type |
|---|---|
instructions | string |
levels | string[] |
Returns
yesNo()
function yesNo(instructions): YesNoQuestion;Build a calibrated yes-or-no question.
Parameters
| Parameter | Type |
|---|---|
instructions | string |
Returns
Human input
HumanReply
What people answered in the run's Linear agent session.
Remarks
Every message sent since the run last read the session counts, including any sent before the question. body holds every message oldest first, each after its author's name; author and createdAt are the newest message's.
Properties
| Property | Type |
|---|---|
author | object |
author.id | string |
author.name | string |
body | string |
createdAt | string |
Halt
type Halt = object;What the question says, in the words a stranger to the repo reads. headline is one plain sentence naming what paused and why, where names the routine it paused in so the footer can say so, about restates the ticket itself, notes are plain bullet lines, and onReply decides what the question asks the human to do: choose between the questions ("continue") or repair something and let the step run again ("retry"). mention adds people, by Linear email, to the operator (or the creator) and the assignee the question already mentions; an email no Linear user has is skipped.
Properties
| Property | Type |
|---|---|
about? | string |
headline | string |
mention? | string[] |
notes? | string[] |
onReply | "continue" | "retry" |
questions? | HaltQuestion[] |
where | string |
HaltOption
type HaltOption = z.infer<typeof haltOptionSchema>;One answer choice for a question shown to a human.
HaltQuestion
type HaltQuestion = z.infer<typeof haltQuestionSchema>;A question shown to a human while a run waits for their reply.
JsonValue
type JsonValue =
| string
| number
| boolean
| null
| JsonValue[]
| {
[key: string]: JsonValue;
};A value that can be serialized as JSON and embedded in a prompt or comment.
haltOptionSchema
const haltOptionSchema: ZodObject<{
label: ZodString;
recommended: ZodOptional<ZodBoolean>;
}, $strict>;Validates an answer choice with a nonempty label and an optional recommendation marker.
haltQuestionSchema
const haltQuestionSchema: ZodObject<{
context: ZodOptional<ZodString>;
options: ZodOptional<ZodArray<ZodObject<{
label: ZodString;
recommended: ZodOptional<ZodBoolean>;
}, $strict>>>;
question: ZodString;
}, $strict>;Validates a question with nonempty text, optional context and optional suggested answers.
Linear tickets
TicketClaim
A ticket held exclusively by the current workflow run, with the Linear agent session the run talks to people in.
Properties
TicketComment
type TicketComment = object;A Linear ticket comment captured in a workflow snapshot.
Properties
| Property | Type |
|---|---|
author | string | null |
body | string |
createdAt | string |
id | string |
TicketLink
type TicketLink = object;A named external link attached to a Linear ticket.
Properties
| Property | Type |
|---|---|
title | string |
url | string |
TicketNote
type TicketNote = object;A note a ticket run posts in its Linear agent session that asks for nothing and suspends nothing. It carries its own words, the way a halt does, so the renderer owns the layout and every caller owns what it says.
Remarks
Linear marks a session stale after about 30 minutes with no activity, and a stale session hides its Stop button. Before a long quiet wait on people, such as a pull request waiting for review, post a note with run: "waiting".
Properties
TicketRef
type TicketRef = object;A compact reference to a related Linear ticket.
Properties
| Property | Type |
|---|---|
id | string |
identifier | string |
title | string |
TicketReviewPrompt()
type TicketReviewPrompt = (input) => string;Renders instructions for an agent to turn a ticket into an actionable handoff.
Parameters
| Parameter | Type |
|---|---|
input | TicketReviewPromptInput |
Returns
string
TicketReviewPromptInput
type TicketReviewPromptInput = object;The rendered ticket supplied to a ticket-review prompt.
Properties
| Property | Type |
|---|---|
ticket | string |
TicketSnapshot
type TicketSnapshot = object;The fixed ticket state shared by every step in one workflow activation.
Properties
| Property | Type |
|---|---|
blockedBy | TicketRef[] |
blocks | TicketRef[] |
branchName | string |
comments | TicketComment[] |
description | string |
fetchedAt | string |
id | string |
identifier | string |
labels | string[] |
links | TicketLink[] |
state | string |
subIssues | TicketRef[] |
title | string |
url | string |
ticketReviewPrompt
const ticketReviewPrompt: TicketReviewPrompt;The default prompt for reviewing a Linear ticket before implementation begins.
ticketReviewVerdictSchema
const ticketReviewVerdictSchema: ZodObject<{
about: ZodString;
assumptions: ZodArray<ZodString>;
brief: ZodString;
questions: ZodArray<ZodObject<{
context: ZodOptional<ZodString>;
options: ZodOptional<ZodArray<ZodObject<{
label: ZodString;
recommended: ZodOptional<ZodBoolean>;
}, $strict>>>;
question: ZodString;
}, $strict>>;
verdict: ZodEnum<{
needs-human: "needs-human";
proceed: "proceed";
}>;
}, $strict>;Structured verdict returned by the agent that reviews a ticket before work starts.
renderTicketSnapshot()
function renderTicketSnapshot(snapshot): string;Render a ticket snapshot as Markdown for an agent prompt.
Parameters
| Parameter | Type |
|---|---|
snapshot | TicketSnapshot |
Returns
string
PagerDuty incidents
IncidentRef
type IncidentRef = object;A PagerDuty object an incident points at, such as its service or an assignee.
Properties
| Property | Type |
|---|---|
id | string |
name | string |
url | string | null |
IncidentSnapshot
type IncidentSnapshot = object;The incident as one workflow activation read it.
Properties
| Property | Type |
|---|---|
assignees | IncidentRef[] |
createdAt | string |
escalationPolicy | IncidentRef |
fetchedAt | string |
id | string |
number | number |
service | IncidentRef |
status | "triggered" | "acknowledged" | "resolved" |
title | string |
urgency | "high" | "low" |
url | string |
Pull requests
CheckRun
A check or commit status reported on a pull request head.
Properties
| Property | Type |
|---|---|
conclusion | string | null |
name | string |
url | string |
MergeOptions
How workflow code asks for a pull request to be merged.
Extends
Properties
| Property | Type | Description |
|---|---|---|
approvalCovers? | ApprovalCoverage | Which commits an approving review covers. Default "latest-commit". |
consent? | MergeConsent | Whose consent the merge needs. Default "operator". |
PullRequestComment
A comment on the pull request conversation, which hangs off no thread.
Properties
| Property | Type |
|---|---|
body | string |
createdAt | string |
id | number |
updatedAt | string |
user | string |
userType | string |
PullRequestMarker
Hidden progress metadata stored in a pull request comment.
Properties
| Property | Type | Description |
|---|---|---|
kind | MarkerKind | reply answers the thing named by source, and status is a note about a commit, such as a stand-down after a refused merge, a CI failure jigs could not repair, or a merge refused for a state that will pass. |
reason? | StatusReason | Required on a status marker, meaningless on any other. |
run | string | The run that wrote it. Provenance for a reader; never matched on. |
scope | string | Names this workflow's work on the pull request. Keep it stable across replacement runs to recognize earlier notes and replies. |
source? | string | What this answers: a comment as id@updatedAt, or a commit sha. |
PullRequestReadOptions
How workflow code asks for a pull request's approval to be read.
Extended by
Properties
| Property | Type | Description |
|---|---|---|
approvalCovers? | ApprovalCoverage | Which commits an approving review covers. Default "latest-commit". |
PullRequestReview
A submitted GitHub review of a pull request.
Properties
| Property | Type |
|---|---|
body | string |
commitSha? | string |
id | number |
state | string |
submittedAt | string |
user | string |
PullRequestSnapshot
GitHub facts about a pull request, without a judgment about outstanding work.
Properties
| Property | Type | Description |
|---|---|---|
appBot | string | The login of the factory's GitHub App, <slug>[bot]: the account jigs posts as, and so do agents whose harness sets github. |
approval | ApprovalState | The operator's consent: how the people's approving reviews read on this head. |
ci | "none" | "pending" | "red" | "green" | none: no check or status has reported on this head yet. It is never green. |
conversationComments | PullRequestComment[] | - |
draft | boolean | - |
failingChecks | CheckRun[] | - |
headSha | string | - |
labels | string[] | Label names on the pull request. |
mergeCommitSha | string | null | The merge commit, once GitHub has made one. |
merged | boolean | - |
mergeState | string | GitHub's own verdict on whether the pull request can merge right now, folding in conflicts, required checks and required reviews. "clean" is the only value that permits a merge; "unknown" means GitHub has not finished computing it, so the answer is "not yet, ask again". |
reviews | PullRequestReview[] | - |
reviewThreads | ReviewThread[] | - |
state | "open" | "closed" | - |
ReviewComment
A comment anchored to a file in a pull request review.
Properties
| Property | Type |
|---|---|
body | string |
createdAt | string |
id | number |
line | number | null |
path | string |
rootId | number |
updatedAt | string |
user | string |
ReviewThread
A pull request review conversation, with its optional file location.
Properties
| Property | Type |
|---|---|
comments | ReviewComment[] |
line | number | null |
origin? | "conversation" |
path | string |
rootId | number |
ApprovalState
type ApprovalState = "approved" | "changes-requested" | "stale" | "none";How the operator's consent reads right now. stale is an approval that named an earlier commit. This differs from a pull request nobody has approved.
PullRequestRef
type PullRequestRef = RepositoryRef & object;Identifies a pull request by its repository, the installation jigs reaches it through, and its number.
Type Declaration
| Name | Type | Description |
|---|---|---|
number | number | The repository-local pull request number. |
RepositoryRef
type RepositoryRef = object;Identifies a repository, and the GitHub installation jigs reaches it through.
Properties
StatusReason
type StatusReason = "merge" | "ci" | "merge-retry";Label a status note as a merge refusal, CI failure or temporary merge refusal. Distinct reasons keep notes for the same commit independent. They do not change merge readiness or schedule more work.
blockedMergeNote()
function blockedMergeNote(snapshot): string | null;The note to leave on a pull request that is approved and green but that GitHub blocks from merging, or null when that is not why it waits.
Parameters
| Parameter | Type |
|---|---|
snapshot | PullRequestSnapshot |
Returns
string | null
Remarks
GitHub does not say which branch rule blocks the merge, so without a note jigs would wait in silence.
defaultPullRequestScope()
function defaultPullRequestScope(subject): string;The scope a caller gets when it names none: this workflow's function name and the subject it was given: a ticket key or the pull request itself. Pass an explicit scope to continue another workflow's work, or to review a pull request independently of the run delivering it.
Parameters
| Parameter | Type |
|---|---|
subject | string |
Returns
string
isPullRequestMergeReady()
function isPullRequestMergeReady(snapshot): boolean;Whether current GitHub facts satisfy the configured approval and merge requirements.
Parameters
| Parameter | Type |
|---|---|
snapshot | PullRequestSnapshot |
Returns
boolean
parseMarkers()
function parseMarkers(body): PullRequestMarker[];Every marker in one comment body, in the order they appear.
Parameters
| Parameter | Type |
|---|---|
body | string |
Returns
pullRequestSnapshotKey()
function pullRequestSnapshotKey(snapshot): string;A comparison key for the facts in a pull request snapshot.
Parameters
| Parameter | Type |
|---|---|
snapshot | PullRequestSnapshot |
Returns
string
Remarks
Collection ordering and incidental fields do not change the key. Compare keys for equality; the key format is opaque and is not a durable identifier.
renderChecks()
function renderChecks(failing): string;Render failed checks as a Markdown list for a pull request note.
Parameters
| Parameter | Type |
|---|---|
failing | CheckRun[] |
Returns
string
Pull request delivery
BuildAndReviewOptions
What buildAndReview needs besides the delivery.
Properties
| Property | Type | Description |
|---|---|---|
rounds | number | One round is one build plus one review of what it committed. |
BuildApproved
A change the reviewer approved.
Properties
| Property | Type | Description |
|---|---|---|
ledger | ReviewRound[] | - |
notes | string[] | The non-blocking findings of the approving round, for a person to read. |
outcome | "approved" | - |
reviewedCommit | string | The commit the reviewer approved. Publish exactly this one. |
BuildFacts
What a fresh build prompt is given: the open findings and the diff so far.
Type Parameters
| Type Parameter |
|---|
W |
Properties
| Property | Type | Description |
|---|---|---|
diff | string | Empty before the first commit. |
findings | object[] | - |
work | W | - |
worktree | Worktree | - |
BuildStopped
Why buildAndReview stopped without an approved change. Nothing is pushed: committed work stays in the worktree for the workflow to push or leave.
Remarks
rounds-exhausted carries the blocking findings still open. uncommitted and no-commits mean the builder left uncommitted changes, or committed nothing new, so there was nothing to review.
Properties
| Property | Type | Description |
|---|---|---|
findings | string[] | - |
outcome | "stopped" | - |
reason | "rounds-exhausted" | "uncommitted" | "no-commits" | - |
round | number | The round it stopped in; for rounds-exhausted, the last round. |
Delivery
One piece of work taken to a pull request: what to build, where, and the agents that build, review and describe it.
Remarks
work is yours: only your prompts read it. Give each delivery its own agent session objects: a session holds its agent's conversation, and its name only labels log lines. writer describes the pull request and defaults to builder. Each routine reads only some of these fields, so a full delivery can be passed to all of them.
Type Parameters
| Type Parameter |
|---|
W |
Properties
| Property | Type | Description |
|---|---|---|
builder | AgentSession | - |
key | string | One key per pull request: it scopes the hidden markers on that pull request's notes. |
prompts | DeliveryPrompts<W> | - |
reviewer | AgentSession | - |
work | W | - |
worktree | Worktree | - |
writer? | AgentSession | - |
DeliveryPrompts
The prompts a delivery sends, written by the workflow. jigs adds only the line that tells each agent the shape of its answer.
Remarks
A turn with two forms goes to an agent session: resume is sent to an agent that holds the earlier turns, so it says only what is new, and fresh to one starting from nothing, so it says everything. describe is sent either way.
Type Parameters
| Type Parameter |
|---|
W |
Properties
Described
A pull request title and body.
Properties
| Property | Type |
|---|---|
body | string |
title | string |
DescribeOptions
What describePullRequest needs besides the delivery.
Properties
FollowOptions
What followPullRequestToOutcome needs besides the delivery and the pull request.
Properties
| Property | Type | Description |
|---|---|---|
approvalCovers | ApprovalCoverage | Which commits a person's approving review covers. |
attemptsPerUpdate | number | Builder turns allowed for each change to the pull request, including recovery. |
mergeWhen | (snapshot) => boolean | Whether you consent to merging this snapshot now. jigs still merges only when GitHub reports the pull request approved, green and clean, so this can only make merging stricter. Return false to leave every merge to a person, or check the snapshot, such as for a label. |
onNeedsHuman | (facts) => Promise<void> | Tell a person the pull request needs them. Watching goes on: the next change to the pull request picks the work back up. The same facts are never sent twice in a row. |
wake | (snapshot, scope) => string[] | The facts in a snapshot that wake the builder, one string each; it is woken for one it has not been shown. scope is the delivery's marker scope. Pass builderWakeFacts for the default rules, or your own function, for example to ignore another bot's comments. |
MaintainFacts
What a maintenance prompt is given: the pull request as GitHub reports it, and any local work the builder has to recover first.
Properties
| Property | Type | Description |
|---|---|---|
news | string[] | The wake facts in snapshot the builder has not been shown, as the wake rule wrote them. Empty when the turn only recovers local work. |
pr | PullRequestRef | - |
recovery? | UnpublishedWork | - |
snapshot | PullRequestSnapshot | - |
PublishOptions
What publishPullRequest needs besides the delivery.
Properties
| Property | Type | Description |
|---|---|---|
body | string | - |
commit | string | The commit to publish. It must be the worktree's HEAD, with nothing uncommitted. |
draft? | boolean | - |
title | string | - |
ReviewFacts
What a fresh review prompt is given: the commit under review and every earlier round.
Type Parameters
| Type Parameter |
|---|
W |
Properties
| Property | Type |
|---|---|
diff | string |
headSha | string |
ledger | ReviewRound[] |
work | W |
worktree | Worktree |
ReviewRound
One build and the review of what it committed.
Properties
UnpublishedWork
Local work the pull request has never had: uncommitted changes, or a local commit that was not pushed. It holds back a merge until it is published.
Properties
| Property | Type |
|---|---|
dirty | boolean |
localHead | string |
pullRequestHead | string |
BuildDelivery
type BuildDelivery<W> = Pick<Delivery<W>, "work" | "worktree" | "builder" | "reviewer"> & object;The parts of a delivery buildAndReview reads.
Type Declaration
| Name | Type |
|---|---|
prompts | Pick<DeliveryPrompts<W>, "build" | "review"> |
Type Parameters
| Type Parameter |
|---|
W |
BuildResult
type BuildResult = BuildApproved | BuildStopped;What buildAndReview returns: an approved change, or a stop.
DescribeDelivery
type DescribeDelivery<W> = Pick<Delivery<W>, "work" | "worktree" | "builder" | "writer"> & object;The parts of a delivery describePullRequest reads.
Type Declaration
| Name | Type |
|---|---|
prompts | Pick<DeliveryPrompts<W>, "describe"> |
Type Parameters
| Type Parameter |
|---|
W |
FindingResponse
type FindingResponse = z.output<typeof findingResponse>;The builder's answer to one finding: what it changed, or why it changed nothing.
FollowDelivery
type FollowDelivery<W> = Pick<Delivery<W>, "work" | "key" | "worktree" | "builder"> & object;The parts of a delivery followPullRequestToOutcome reads.
Type Declaration
| Name | Type |
|---|---|
prompts | Pick<DeliveryPrompts<W>, "maintain"> |
Type Parameters
| Type Parameter |
|---|
W |
FollowResult
type FollowResult =
| {
outcome: "merged";
}
| {
outcome: "closed";
};How followPullRequestToOutcome ended: the pull request merged, or closed unmerged.
NeedsHuman
type NeedsHuman =
| {
detail: string;
reason: "builder-asked" | "attempts-exhausted";
unpublished?: UnpublishedWork;
}
| {
detail: string;
reason: "merge-refused";
tries: number;
}
| {
detail: string;
headSha: string;
reason: "merge-blocked";
};Why a pull request needs a person, as facts for the workflow to word and send.
Remarks
builder-asked: the builder said it needs a person;detailis its summary.attempts-exhausted: the builder's attempts for one pull request update ran out with local work still unpublished;detailis its last summary.merge-refused: GitHub refused the merge;detailis the last refusal andtrieshow often jigs tried. A transient refusal is retried up to ten times before it is reported.merge-blocked: GitHub blocks an approved, green pull request from merging, usually because of a branch rule;detailsays so in a sentence. Sent once per head. Mark a note posted about it withheadShaand the delivery's scope, so it does not wake the builder and a later run does not post it again.
unpublished is set when local work the pull request has never had holds back the merge. The local worktree path never appears in detail.
PublishDelivery
type PublishDelivery = Pick<Delivery<unknown>, "worktree">;The parts of a delivery publishPullRequest reads.
ReviewFinding
type ReviewFinding = z.output<typeof reviewFinding>;One finding from a review of the change.
builderWakeFacts()
function builderWakeFacts(snapshot, scope): string[];The default wake rule for followPullRequestToOutcome: the facts in a snapshot a builder can act on, one string each.
Parameters
| Parameter | Type |
|---|---|
snapshot | PullRequestSnapshot |
scope | string |
Returns
string[]
Remarks
A review with a body or one requesting changes, a new comment or a person's edit of one, a check failing on the current head, and a conflict with the base each wake the builder. Checks that queue, run or pass, a bare approval, label changes, a bot editing its own comment, the App bot's unmarked comments (the builder's own replies) and notes marked with the delivery's scope wake nothing. To change the rules, wrap it or pass your own function as wake.
Example
import { builderWakeFacts, type PullRequestSnapshot } from "@jigs-ai/jigs";
// Also ignore a coverage bot's comments.
const wake = (snapshot: PullRequestSnapshot, scope: string) =>
builderWakeFacts(
{
...snapshot,
conversationComments: snapshot.conversationComments.filter(
(comment) => comment.user !== "codecov[bot]",
),
},
scope,
);Slack messages
SlackAuthor
Someone who posted in Slack.
Remarks
id is the Slack user ID, or the bot ID for an integration that posts without a user. email is missing for bots. isOwnBot marks the factory's own bot, which is what posts every message jigs sends.
Properties
| Property | Type |
|---|---|
bot | boolean |
email? | string |
id | string |
isOwnBot | boolean |
name | string |
SlackPost
One Slack message: its timestamp, which is also its ID in the channel, its mrkdwn text and who wrote it.
Properties
| Property | Type |
|---|---|
author | SlackAuthor |
text | string |
ts | string |
SlackQuestion
The thread a wait reads, named by the ts of its top-level message (never a reply's). lastRead is the ts of the newest post the workflow has read, never its own question; only human replies after it count. until, an ISO 8601 timestamp, is when to stop waiting.
Properties
SlackMessageSnapshot
type SlackMessageSnapshot =
| {
channel: string;
gone: true;
ts: string;
}
| SlackPost & object;A Slack message and its thread, as fetchSlackMessage read them, or gone when the message was deleted.
Remarks
replies are the thread's replies, oldest first, without the message itself.
SlackReplyResult
type SlackReplyResult =
| {
outcome: "replied";
replies: SlackPost[];
}
| {
outcome: "timed-out";
}
| {
outcome: "gone";
};How waitForSlackReply ended: replied with the new human replies (oldest first, never empty), timed-out at until, or gone when the thread's top-level message was deleted.
Git/change data
ChangePatch
Patches for selected paths between two resolved commits.
Properties
| Property | Type | Description |
|---|---|---|
patches | object[] | Patch text for each selected path, in first-requested order. |
truncated | boolean | Whether the shared text limit cut off any patch text. |
ChangeSummary
A bounded description of the committed changes between two Git refs.
Properties
| Property | Type | Description |
|---|---|---|
base | string | The resolved base commit. |
commits | object[] | Commits reachable from head but not base, newest first. |
files | FileChange[] | Files that differ directly between the base and head trees. |
head | string | The resolved head commit. |
truncated | boolean | Whether file or commit limits caused results to be omitted. |
FileChange
One file changed between the base and head trees.
Properties
| Property | Type | Description |
|---|---|---|
additions | number | The number of added lines, or zero for a binary file. |
deletions | number | The number of deleted lines, or zero for a binary file. |
path | string | The changed path. Renames use the path in the head tree. |
status | ChangeStatus | How the path differs between the two trees. |
ChangeStatus
type ChangeStatus = "added" | "modified" | "deleted" | "renamed" | "other";How a file differs between the base and head trees.
renderChangeSummary()
function renderChangeSummary(summary): string;Render a Markdown review summary with commits, totals and up to 60 changed-file rows.
Parameters
| Parameter | Type |
|---|---|
summary | ChangeSummary |
Returns
string
Runtime and resources
PullRequestWorktree
A worktree checked out at a pull request's head commit, with no branch of its own.
Remarks
It is for checking the pull request as it stands, so it cannot be pushed. Pass headSha to mergePullRequest to merge exactly the commit that was checked. Commits made in it are not kept when the run's resources are released.
Properties
ReleaseReport
The result of applying a release policy to one run's resources.
Properties
| Property | Type | Description |
|---|---|---|
policy | object | The policy applied by this release attempt. |
policy.onFailure | "release" | "keep" | What to do with eligible resources after a failed or cancelled run. |
policy.onSuccess | "release" | "keep" | What to do with eligible resources after a completed run. |
resources | ResourceRecord[] | Every resource the run recorded, with its state and reason after this attempt. |
ResourceRecord
One recorded resource and what has happened to it. Records stay after release as history.
Extends
Properties
| Property | Type | Description |
|---|---|---|
identity | string | The stable name that distinguishes this resource from others of the same kind. |
kind | string | The resource category, such as worktree or run-directory. |
reason | string | null | Why the resource is in its state, or null while it is live and untouched. |
runId | string | The run that owns the resource. |
state | ResourceState | - |
updatedAt | string | When the state last changed, as an ISO timestamp. |
url | string | An absolute URL where a human can inspect the resource. |
RunResource
A durable thing that a run created or otherwise owns a reference to.
Extended by
Properties
Worktree
A provisioned repository worktree and the commit it was cut from.
Properties
ReleasePolicy
type ReleasePolicy = z.input<typeof releaseSchema>;Selects whether eligible run resources are released for each terminal outcome.
ResourceState
type ResourceState = "live" | "kept" | "released" | "failed";Where a recorded resource stands: live until release decides, then kept by policy or a safety check, released, or failed when the release attempt errored and will be retried.
Errors and utilities
ClaimConflictError
A ticket-claim failure that identifies the run already holding the ticket.
Extends
Error
Constructors
Constructor
new ClaimConflictError(resource, owningRunId): ClaimConflictError;Parameters
| Parameter | Type |
|---|---|
resource | string |
owningRunId | string |
Returns
Overrides
Error.constructorProperties
| Property | Type |
|---|---|
owningRunId | string |
resource | string |
JigsError
An operator-readable failure that is safe to construct inside a workflow.
Extends
Error
Extended by
Constructors
Constructor
new JigsError(message, hint?): JigsError;Parameters
| Parameter | Type |
|---|---|
message | string |
hint? | string |
Returns
Overrides
Error.constructorProperties
JitCheckError
A failed just-in-time tool check, with repair details for each failure.
Extends
Error
Constructors
Constructor
new JitCheckError(failures): JitCheckError;Parameters
| Parameter | Type |
|---|---|
failures | object & object[] |
Returns
Overrides
Error.constructorProperties
| Property | Type |
|---|---|
failures | object & object[] |
interpolate()
function interpolate(template, values): string;Replace named once, leaving unknown names unchanged.
Parameters
| Parameter | Type |
|---|---|
template | string |
values | Record<string, string> |
Returns
string
unreachable()
function unreachable(value): never;Fail an exhaustive branch if an unexpected value reaches it at runtime.
Parameters
| Parameter | Type |
|---|---|
value | never |
Returns
never
Factory plumbing
AgentRequest
type AgentRequest =
| Omit<RunAgentOptions, "output"> & object
| Omit<AskAgentOptions, "output"> & object;Serializable agent request passed to a durable step.
ModelRequest
type ModelRequest = Omit<AskModelOptions, "output"> & object;Serializable API model request passed to a durable step.
Type Declaration
| Name | Type |
|---|---|
outputSchema? | OutputJsonSchema |
Linear agent sessions
LinearAgentConversationOptions
How a Linear agent conversation runs: the Claude harness and the worktree it works in.
Remarks
instructions lead the first message Claude reads, which carries Linear's context for the session when Linear sends one. The conversation ends once no one has replied for idleFor, a duration such as "30m" or milliseconds; four hours by default.
Properties
| Property | Type |
|---|---|
cwd | string |
harness | Harness |
idleFor? | | number | `${number}s` | `${number}d` | `${number}h` | `${number}m` |
instructions? | string |
LinearAgentConversationResult
type LinearAgentConversationResult =
| {
outcome: "idle" | "stopped";
turns: number;
}
| {
error: string;
outcome: "failed";
turns: number;
};How a Linear agent conversation ended, and how many turns it ran.
Type Aliases
ApprovalCoverage
type ApprovalCoverage = "latest-commit" | "any-commit";Which commits an approving review covers, chosen in workflow code.
Remarks
latest-commit, the default, counts an approval only on the commit it names, so a push withdraws it. any-commit keeps a person's approval counting through later pushes until a later review requests changes or the approval is dismissed; approvals by a bot, such as an agent acting as the factory's GitHub App, never count.
MergeConsent
type MergeConsent = "operator" | "workflow";Whose consent a merge needs, chosen in workflow code for each merge.
Remarks
operator, the default, needs a person's approving review. workflow lets the workflow's own checks stand in for it, for a workflow that judges a pull request itself, such as one that tests a dependency update before merging it. Every other merge requirement still holds, and a review requesting changes still stops the merge.