@markjaquith/agency 2.68.0 → 2.69.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -54,7 +54,8 @@ interface HarnessOptions {
54
54
  readonly materializeError?: Error
55
55
  readonly available?: Readonly<Record<string, boolean>>
56
56
  readonly chooserCommand?: readonly string[]
57
- readonly runners?: Record<
57
+ readonly agent?: "opencode2" | "opencode" | "pi" | "claude"
58
+ readonly agents?: Record<
58
59
  string,
59
60
  {
60
61
  command: readonly [string, ...string[]]
@@ -121,6 +122,7 @@ const createHarness = (options: HarnessOptions = {}) => {
121
122
  },
122
123
  }
123
124
  const workbase = {
125
+ loadGlobalConfig: () => Effect.succeed({ agent: options.agent }),
124
126
  discover: (path: string) =>
125
127
  options.outsideWorkbase && path === "/outside"
126
128
  ? Effect.fail({
@@ -136,7 +138,7 @@ const createHarness = (options: HarnessOptions = {}) => {
136
138
  config: {
137
139
  version: 2 as const,
138
140
  chooserCommand: options.chooserCommand,
139
- runners: options.runners,
141
+ agents: options.agents,
140
142
  },
141
143
  }),
142
144
  repositoryAliases: () => Effect.succeed(["agency"]),
@@ -307,8 +309,11 @@ const createHarness = (options: HarnessOptions = {}) => {
307
309
  commandOptions: Parameters<typeof work>[0],
308
310
  pick: PickWorkTarget = defaultPick,
309
311
  pickBase: PickWorkbase = defaultPickWorkbase,
310
- ) =>
311
- Effect.runPromise(
312
+ preserveSession = false,
313
+ ) => {
314
+ const agencySessionId = process.env.AGENCY_SESSION_ID
315
+ if (!preserveSession) delete process.env.AGENCY_SESSION_ID
316
+ return Effect.runPromise(
312
317
  work(commandOptions, launch, pick, progress, pickBase).pipe(
313
318
  Effect.provideService(WorktreeService, worktrees as never),
314
319
  Effect.provideService(FileSystemService, fs as never),
@@ -319,7 +324,12 @@ const createHarness = (options: HarnessOptions = {}) => {
319
324
  Effect.provideService(ReadinessService, readiness as never),
320
325
  Effect.provideService(IntegrationService, integrations as never),
321
326
  ) as Effect.Effect<void, unknown, never>,
322
- )
327
+ ).finally(() => {
328
+ if (agencySessionId !== undefined) {
329
+ process.env.AGENCY_SESSION_ID = agencySessionId
330
+ }
331
+ })
332
+ }
323
333
  const runPrepare = (commandOptions: Parameters<typeof workPrepare>[0]) =>
324
334
  Effect.runPromise(
325
335
  workPrepare(commandOptions).pipe(
@@ -805,7 +815,7 @@ describe("work command", () => {
805
815
 
806
816
  await expect(
807
817
  harness.run({ taskId: "example", opencode: true, claude: true }),
808
- ).rejects.toThrow("Cannot combine --runner, --opencode, and --claude")
818
+ ).rejects.toThrow("Cannot combine --agent, --opencode, and --claude")
809
819
  expect(harness.events).toEqual([])
810
820
  })
811
821
 
@@ -897,12 +907,17 @@ describe("work command", () => {
897
907
  const harness = createHarness({ workspace: multiPhaseWorkspace })
898
908
  process.env.AGENCY_SESSION_ID = "existing-session"
899
909
  try {
900
- await harness.run({
901
- taskId: "example",
902
- phaseId: "implementation",
903
- opencode: true,
904
- auto: true,
905
- })
910
+ await harness.run(
911
+ {
912
+ taskId: "example",
913
+ phaseId: "implementation",
914
+ opencode: true,
915
+ auto: true,
916
+ },
917
+ undefined,
918
+ undefined,
919
+ true,
920
+ )
906
921
  } finally {
907
922
  delete process.env.AGENCY_SESSION_ID
908
923
  }
@@ -919,10 +934,10 @@ describe("work command", () => {
919
934
  })
920
935
  })
921
936
 
922
- test("expands a named runner with shared context", async () => {
937
+ test("expands a named agent with shared context", async () => {
923
938
  const harness = createHarness({
924
939
  available: { codex: true },
925
- runners: {
940
+ agents: {
926
941
  custom: {
927
942
  command: ["codex"],
928
943
  autoCommand: ["codex", "--task", "{task}", "{prompt}"],
@@ -934,7 +949,7 @@ describe("work command", () => {
934
949
  },
935
950
  })
936
951
 
937
- await harness.run({ taskId: "example", runner: "custom", auto: true })
952
+ await harness.run({ taskId: "example", agent: "custom", auto: true })
938
953
 
939
954
  expect(harness.probes).toEqual(["codex"])
940
955
  expect(harness.launches[0]).toEqual({
@@ -948,7 +963,7 @@ describe("work command", () => {
948
963
  cwd: taskDirectory,
949
964
  })
950
965
  expect(harness.launchEnvironments[0]).toMatchObject({
951
- AGENCY_RUNNER: "custom",
966
+ AGENCY_AGENT: "custom",
952
967
  AGENCY_CLAIMANT: process.env.USER ?? "agency",
953
968
  AGENCY_WORKBASE: "/workbase",
954
969
  AGENCY_TARGET: "execution-unit:task/example",
@@ -962,7 +977,7 @@ describe("work command", () => {
962
977
  test("prints the exact command contract without launching and omits secrets", async () => {
963
978
  const harness = createHarness({
964
979
  available: { agent: true },
965
- runners: {
980
+ agents: {
966
981
  custom: {
967
982
  command: ["agent"],
968
983
  autoCommand: ["agent", "{prompt}"],
@@ -977,7 +992,7 @@ describe("work command", () => {
977
992
  const output = await captureLogs(() =>
978
993
  harness.run({
979
994
  taskId: "example",
980
- runner: "custom",
995
+ agent: "custom",
981
996
  printCommand: true,
982
997
  }),
983
998
  )
@@ -1078,12 +1093,12 @@ describe("work command", () => {
1078
1093
 
1079
1094
  test("automatically falls back from OpenCode to Claude", async () => {
1080
1095
  const harness = createHarness({
1081
- available: { opencode2: false, opencode: false },
1096
+ available: { opencode2: false, opencode: false, pi: false },
1082
1097
  })
1083
1098
 
1084
1099
  await harness.run({ taskId: "example" })
1085
1100
 
1086
- expect(harness.probes).toEqual(["opencode2", "opencode", "claude"])
1101
+ expect(harness.probes).toEqual(["opencode2", "opencode", "pi", "claude"])
1087
1102
  expect(harness.launches[0]).toEqual({
1088
1103
  cli: "claude",
1089
1104
  args: ["claude"],
@@ -1091,6 +1106,38 @@ describe("work command", () => {
1091
1106
  })
1092
1107
  })
1093
1108
 
1109
+ test("automatically falls back from OpenCode to Pi", async () => {
1110
+ const harness = createHarness({
1111
+ available: { opencode2: false, opencode: false },
1112
+ })
1113
+
1114
+ await harness.run({ taskId: "example" })
1115
+
1116
+ expect(harness.probes).toEqual(["opencode2", "opencode", "pi"])
1117
+ expect(harness.launches[0]).toMatchObject({ cli: "pi", args: ["pi"] })
1118
+ })
1119
+
1120
+ test("uses the global agent before automatic detection", async () => {
1121
+ const harness = createHarness({ agent: "pi" })
1122
+
1123
+ await harness.run({ taskId: "example" })
1124
+
1125
+ expect(harness.probes).toEqual(["pi"])
1126
+ expect(harness.launches[0]).toMatchObject({ cli: "pi", args: ["pi"] })
1127
+ })
1128
+
1129
+ test("lets an invocation agent override the global agent", async () => {
1130
+ const harness = createHarness({ agent: "pi" })
1131
+
1132
+ await harness.run({ taskId: "example", agent: "claude" })
1133
+
1134
+ expect(harness.probes).toEqual(["claude"])
1135
+ expect(harness.launches[0]).toMatchObject({
1136
+ cli: "claude",
1137
+ args: ["claude"],
1138
+ })
1139
+ })
1140
+
1094
1141
  test("does not fall back when OpenCode is explicitly required", async () => {
1095
1142
  const harness = createHarness({ available: { opencode: false } })
1096
1143
 
@@ -1117,13 +1164,18 @@ describe("work command", () => {
1117
1164
 
1118
1165
  test("fails when neither agent tool is available", async () => {
1119
1166
  const harness = createHarness({
1120
- available: { opencode2: false, opencode: false, claude: false },
1167
+ available: {
1168
+ opencode2: false,
1169
+ opencode: false,
1170
+ pi: false,
1171
+ claude: false,
1172
+ },
1121
1173
  })
1122
1174
 
1123
1175
  await expect(harness.run({ taskId: "example" })).rejects.toThrow(
1124
1176
  "claude CLI tool not found",
1125
1177
  )
1126
- expect(harness.probes).toEqual(["opencode2", "opencode", "claude"])
1178
+ expect(harness.probes).toEqual(["opencode2", "opencode", "pi", "claude"])
1127
1179
  expect(harness.launches).toEqual([])
1128
1180
  })
1129
1181
 
@@ -26,9 +26,9 @@ import {
26
26
  } from "../workbase/workbase-choice"
27
27
  import {
28
28
  printableEnvironment,
29
- resolveRunnerCommand,
30
- runnerEnvironment,
31
- } from "../workbase/runner-command"
29
+ resolveAgentCommand,
30
+ agentEnvironment,
31
+ } from "../workbase/agent-command"
32
32
  import {
33
33
  assessValidationEvidence,
34
34
  buildKickoffPlan,
@@ -44,7 +44,7 @@ export interface WorkOptions extends BaseCommandOptions {
44
44
  readonly epicId?: string
45
45
  readonly opencode?: boolean
46
46
  readonly claude?: boolean
47
- readonly runner?: string
47
+ readonly agent?: string
48
48
  readonly printCommand?: boolean
49
49
  readonly auto?: boolean
50
50
  readonly force?: boolean
@@ -94,10 +94,10 @@ export const work = (
94
94
  Effect.gen(function* () {
95
95
  if (
96
96
  (options.opencode && options.claude) ||
97
- (options.runner && (options.opencode || options.claude))
97
+ (options.agent && (options.opencode || options.claude))
98
98
  ) {
99
99
  return yield* Effect.fail(
100
- new Error("Cannot combine --runner, --opencode, and --claude"),
100
+ new Error("Cannot combine --agent, --opencode, and --claude"),
101
101
  )
102
102
  }
103
103
  const previousEnvironment = { ...process.env }
@@ -132,6 +132,7 @@ export const work = (
132
132
  if (!root) return
133
133
  yield* integrations.sync(root)
134
134
  const { config } = yield* workbase.loadConfig(root)
135
+ const globalConfig = yield* workbase.loadGlobalConfig()
135
136
 
136
137
  let target: WorkTarget | null = null
137
138
  if (options.epicId) {
@@ -274,22 +275,15 @@ export const work = (
274
275
  }
275
276
  prompt = `Agency worker launch target: ${targetNodeId(target)}. ${prompt}`
276
277
 
277
- const explicitlyRequested = Boolean(
278
- options.runner ||
279
- options.opencode ||
280
- options.claude ||
281
- process.env.AGENCY_RUNNER,
282
- )
283
- const defaultRunners = ["opencode2", "opencode", "claude"] as const
284
- let defaultRunnerIndex = 0
285
- let runner: string =
286
- options.runner ??
287
- process.env.AGENCY_RUNNER ??
288
- (options.claude
289
- ? "claude"
290
- : options.opencode
291
- ? "opencode"
292
- : defaultRunners[defaultRunnerIndex]!)
278
+ const invocationAgent =
279
+ options.agent ??
280
+ process.env.AGENCY_AGENT ??
281
+ (options.claude ? "claude" : options.opencode ? "opencode" : undefined)
282
+ const selectedAgent = invocationAgent ?? globalConfig.agent
283
+ const explicitlyRequested = selectedAgent !== undefined
284
+ const defaultAgents = ["opencode2", "opencode", "pi", "claude"] as const
285
+ let defaultAgentIndex = 0
286
+ let agent: string = selectedAgent ?? defaultAgents[defaultAgentIndex]!
293
287
  const claimant = process.env.AGENCY_CLAIMANT ?? process.env.USER ?? "agency"
294
288
  const sessionId =
295
289
  process.env.AGENCY_SESSION_ID ?? `${process.pid}-${Date.now()}`
@@ -306,9 +300,9 @@ export const work = (
306
300
  sessionId,
307
301
  claimRevision: "",
308
302
  }
309
- let resolved = resolveRunnerCommand(
310
- runner,
311
- config.runners,
303
+ let resolved = resolveAgentCommand(
304
+ agent,
305
+ config.agents,
312
306
  variables,
313
307
  resume,
314
308
  options.auto,
@@ -320,12 +314,12 @@ export const work = (
320
314
  while (
321
315
  available.exitCode !== 0 &&
322
316
  !explicitlyRequested &&
323
- defaultRunnerIndex < defaultRunners.length - 1
317
+ defaultAgentIndex < defaultAgents.length - 1
324
318
  ) {
325
- runner = defaultRunners[++defaultRunnerIndex]!
326
- resolved = resolveRunnerCommand(
327
- runner,
328
- config.runners,
319
+ agent = defaultAgents[++defaultAgentIndex]!
320
+ resolved = resolveAgentCommand(
321
+ agent,
322
+ config.agents,
329
323
  variables,
330
324
  resume,
331
325
  options.auto,
@@ -336,9 +330,9 @@ export const work = (
336
330
  if (available.exitCode !== 0) {
337
331
  return yield* Effect.fail(new Error(`${cli} CLI tool not found`))
338
332
  }
339
- resolved = resolveRunnerCommand(
340
- runner,
341
- config.runners,
333
+ resolved = resolveAgentCommand(
334
+ agent,
335
+ config.agents,
342
336
  variables,
343
337
  resume,
344
338
  options.auto,
@@ -346,7 +340,7 @@ export const work = (
346
340
  cli = resolved.argv[0]!
347
341
  const environment = {
348
342
  ...resolved.environment,
349
- ...runnerEnvironment(runner, variables),
343
+ ...agentEnvironment(agent, variables),
350
344
  }
351
345
  if (writablePath) environment.AGENCY_WRITABLE_CHECKOUT = writablePath
352
346
  if (options.printCommand) {
@@ -579,7 +573,7 @@ export const workPrepare = (options: WorkOptions = {}) =>
579
573
  })
580
574
 
581
575
  export const help = `
582
- Usage: agency work [<directory-or-task-id> | --epic <epic-id>] [--runner <name>] [--auto]
576
+ Usage: agency work [<directory-or-task-id> | --epic <epic-id>] [--agent <name>] [--auto]
583
577
  agency work prepare [target] [--evidence <json-or-path>] [--dry-run] [--json]
584
578
 
585
579
  Launch an agent for an epic, task, or phase. With no directory, select one
@@ -587,7 +581,7 @@ interactively. A positional argument resolves as a directory first, then as a ta
587
581
  ID. Use '.' for the current directory. Outside a workbase, select a registered
588
582
  workbase first. Managed OpenCode launches receive whole-workbase access through
589
583
  Agency's project plugin; Agency context remains authoritative for writes. Automatic
590
- runner discovery checks opencode2, opencode, then claude.
584
+ agent discovery checks opencode2, opencode, pi, then claude.
591
585
 
592
586
  The prepare subcommand resolves and materializes an execution workspace without
593
587
  launching an agent or changing lifecycle status. --dry-run reports planned Git
@@ -603,8 +597,8 @@ Options:
603
597
  --phase <id> Work on a phase selected with --task
604
598
  --workbase <target> Select a workbase by ID, name, or path
605
599
  --cwd <path> Resolve context from a specific directory
606
- --runner <name> Select a configured runner or built-in preset
607
- --auto Send the generated context prompt to the runner
600
+ --agent <name> Select a configured agent or built-in preset
601
+ --auto Send the generated context prompt to the agent
608
602
  --print-command Print cwd, argv, and non-secret environment without launch
609
603
  --opencode Require the OpenCode preset
610
604
  --claude Require the Claude Code preset
@@ -124,7 +124,7 @@ describe("machine protocol", () => {
124
124
  currentRevision: "a".repeat(64),
125
125
  claim: {
126
126
  claimant: "orchestrator",
127
- runner: "agent",
127
+ agent: "agent",
128
128
  sessionId: "job-1",
129
129
  startedAt: "2026-07-17T12:00:00.000Z",
130
130
  targetRevision: "0".repeat(64),
@@ -137,7 +137,7 @@ describe("machine protocol", () => {
137
137
  retryable: true,
138
138
  fields: {
139
139
  target: "task 'example'",
140
- claim: { runner: "agent", sessionId: "job-1" },
140
+ claim: { agent: "agent", sessionId: "job-1" },
141
141
  },
142
142
  },
143
143
  })
@@ -324,7 +324,7 @@ describe("ArchiveService bulk task archive", () => {
324
324
  `status: dropped
325
325
  claim:
326
326
  claimant: orchestrator
327
- runner: opencode
327
+ agent: opencode
328
328
  sessionId: task-session
329
329
  startedAt: 2026-08-07T00:00:00.000Z
330
330
  targetRevision: ${"a".repeat(64)}
@@ -373,7 +373,7 @@ claim:
373
373
  `status: dropped
374
374
  claim:
375
375
  claimant: orchestrator
376
- runner: opencode
376
+ agent: opencode
377
377
  sessionId: phase-session
378
378
  startedAt: 2026-08-07T00:00:00.000Z
379
379
  targetRevision: ${"b".repeat(64)}
@@ -56,7 +56,7 @@ describe("claim service", () => {
56
56
  {
57
57
  taskId: "single",
58
58
  claimant: "orchestrator-1",
59
- runner: "agent-1",
59
+ agent: "agent-1",
60
60
  sessionId,
61
61
  revision,
62
62
  now,
@@ -79,7 +79,7 @@ describe("claim service", () => {
79
79
 
80
80
  expect(acquired.claim).toEqual({
81
81
  claimant: "orchestrator-1",
82
- runner: "agent-1",
82
+ agent: "agent-1",
83
83
  sessionId: "session-1",
84
84
  startedAt: "2026-07-17T12:00:00.000Z",
85
85
  targetRevision: initial.revision,
@@ -315,7 +315,7 @@ describe("claim service", () => {
315
315
  taskId: "multi",
316
316
  phaseId: "implementation",
317
317
  claimant: "orchestrator",
318
- runner: "agent",
318
+ agent: "agent",
319
319
  sessionId: "phase-session",
320
320
  revision: phase.revision,
321
321
  },
@@ -70,7 +70,7 @@ interface ClaimInput {
70
70
  readonly taskId: string
71
71
  readonly phaseId?: string
72
72
  readonly claimant: string
73
- readonly runner: string
73
+ readonly agent: string
74
74
  readonly sessionId: string
75
75
  readonly revision: string
76
76
  readonly expiresAt?: string
@@ -401,7 +401,7 @@ export class ClaimService extends Effect.Service<ClaimService>()(
401
401
  Effect.gen(function* () {
402
402
  for (const [label, value] of [
403
403
  ["Claimant", input.claimant],
404
- ["Runner", input.runner],
404
+ ["Agent", input.agent],
405
405
  ["Session ID", input.sessionId],
406
406
  ] as const) {
407
407
  assertIdentity(label, value)
@@ -435,7 +435,7 @@ export class ClaimService extends Effect.Service<ClaimService>()(
435
435
  target: inspected.target.label,
436
436
  currentRevision: input.revision,
437
437
  claim: data.claim,
438
- message: `${inspected.target.label} is claimed by '${data.claim.runner}'`,
438
+ message: `${inspected.target.label} is claimed by '${data.claim.agent}'`,
439
439
  })
440
440
  }
441
441
  if (
@@ -457,7 +457,7 @@ export class ClaimService extends Effect.Service<ClaimService>()(
457
457
  }
458
458
  const claim: ClaimRecord = {
459
459
  claimant: input.claimant.trim(),
460
- runner: input.runner.trim(),
460
+ agent: input.agent.trim(),
461
461
  sessionId: input.sessionId.trim(),
462
462
  startedAt: operationTime.toISOString(),
463
463
  targetRevision: input.revision,
@@ -138,16 +138,16 @@ export class DoctorService extends Effect.Service<DoctorService>()(
138
138
  const versionControlAvailable =
139
139
  gitAvailable && (config.vcs !== "jj" || jjAvailable)
140
140
  yield* tool(
141
- "capability.runner.opencode",
141
+ "capability.agent.opencode",
142
142
  "opencode",
143
143
  "optional",
144
- "OpenCode runner",
144
+ "OpenCode agent",
145
145
  )
146
146
  yield* tool(
147
- "capability.runner.claude",
147
+ "capability.agent.claude",
148
148
  "claude",
149
149
  "optional",
150
- "Claude runner",
150
+ "Claude agent",
151
151
  )
152
152
 
153
153
  const configuredCommands: readonly (readonly [
@@ -194,43 +194,43 @@ export class DoctorService extends Effect.Service<DoctorService>()(
194
194
  ]
195
195
  : [],
196
196
  ),
197
- ...Object.entries(config.runners ?? {}).map(
198
- ([name, runner]) =>
197
+ ...Object.entries(config.agents ?? {}).map(
198
+ ([name, agent]) =>
199
199
  [
200
- `integration.runner.${name}`,
201
- runner.command,
202
- `Configured runner '${name}'`,
200
+ `integration.agent.${name}`,
201
+ agent.command,
202
+ `Configured agent '${name}'`,
203
203
  ] as const,
204
204
  ),
205
- ...Object.entries(config.runners ?? {}).flatMap(([name, runner]) =>
206
- runner.autoCommand
205
+ ...Object.entries(config.agents ?? {}).flatMap(([name, agent]) =>
206
+ agent.autoCommand
207
207
  ? [
208
208
  [
209
- `integration.runner.${name}.auto`,
210
- runner.autoCommand,
211
- `Configured runner '${name}' auto`,
209
+ `integration.agent.${name}.auto`,
210
+ agent.autoCommand,
211
+ `Configured agent '${name}' auto`,
212
212
  ] as const,
213
213
  ]
214
214
  : [],
215
215
  ),
216
- ...Object.entries(config.runners ?? {}).flatMap(([name, runner]) =>
217
- runner.resumeCommand
216
+ ...Object.entries(config.agents ?? {}).flatMap(([name, agent]) =>
217
+ agent.resumeCommand
218
218
  ? [
219
219
  [
220
- `integration.runner.${name}.resume`,
221
- runner.resumeCommand,
222
- `Configured runner '${name}' resume`,
220
+ `integration.agent.${name}.resume`,
221
+ agent.resumeCommand,
222
+ `Configured agent '${name}' resume`,
223
223
  ] as const,
224
224
  ]
225
225
  : [],
226
226
  ),
227
- ...Object.entries(config.runners ?? {}).flatMap(([name, runner]) =>
228
- runner.autoResumeCommand
227
+ ...Object.entries(config.agents ?? {}).flatMap(([name, agent]) =>
228
+ agent.autoResumeCommand
229
229
  ? [
230
230
  [
231
- `integration.runner.${name}.auto-resume`,
232
- runner.autoResumeCommand,
233
- `Configured runner '${name}' auto resume`,
231
+ `integration.agent.${name}.auto-resume`,
232
+ agent.autoResumeCommand,
233
+ `Configured agent '${name}' auto resume`,
234
234
  ] as const,
235
235
  ]
236
236
  : [],
@@ -131,7 +131,7 @@ describe("IntegrationService", () => {
131
131
  "call Herdr help, skill, or CLI discovery",
132
132
  )
133
133
  expect(managedWorkbaseAgents).toContain("exactly one final")
134
- expect(managedWorkbaseAgents).toContain("leave the runner in the")
134
+ expect(managedWorkbaseAgents).toContain("leave the agent in the")
135
135
  })
136
136
 
137
137
  test("generates a dynamic workbase plugin", () => {
@@ -777,7 +777,7 @@ describe("IntegrationService", () => {
777
777
  expect(config.agent.agency.hidden).toBeUndefined()
778
778
  expect(config.agent.agency.steps).toBeUndefined()
779
779
  expect(config.agent.agency.prompt).toContain(
780
- "verify that the runner started successfully",
780
+ "verify that the agent started successfully",
781
781
  )
782
782
  expect(config.agent.agency.prompt).toContain(
783
783
  "return without waiting for the task to finish",
@@ -235,7 +235,7 @@ pr: null
235
235
  status: working
236
236
  claim:
237
237
  claimant: orchestrator
238
- runner: opencode
238
+ agent: opencode
239
239
  sessionId: session-1
240
240
  startedAt: 2026-07-20T00:00:00.000Z
241
241
  targetRevision: ${"a".repeat(64)}
@@ -275,7 +275,7 @@ describe("ReviewService", () => {
275
275
  {
276
276
  taskId: "review",
277
277
  claimant: "reviewer",
278
- runner: "opencode",
278
+ agent: "opencode",
279
279
  sessionId: "session",
280
280
  revision: task.revision,
281
281
  },
@@ -311,7 +311,7 @@ describe("ReviewService", () => {
311
311
  {
312
312
  taskId: "review",
313
313
  claimant: "reviewer",
314
- runner: "opencode",
314
+ agent: "opencode",
315
315
  sessionId: "active",
316
316
  revision: task.revision,
317
317
  },