@markjaquith/agency 2.67.0 → 2.69.0

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.
Files changed (36) hide show
  1. package/README.md +61 -33
  2. package/cli-main.ts +2 -2
  3. package/fixtures/protocol/orchestration-recipes.json +2 -2
  4. package/package.json +1 -1
  5. package/schemas/agency-graph-v1.schema.json +2 -2
  6. package/src/cli-parser.test.ts +7 -7
  7. package/src/cli-parser.ts +11 -11
  8. package/src/cli.test.ts +11 -9
  9. package/src/commands/claim.ts +6 -6
  10. package/src/commands/doctor.test.ts +3 -3
  11. package/src/commands/init.test.ts +6 -0
  12. package/src/commands/integration.test.ts +20 -2
  13. package/src/commands/integration.ts +6 -4
  14. package/src/commands/work.test.ts +74 -22
  15. package/src/commands/work.ts +32 -38
  16. package/src/protocol.test.ts +2 -2
  17. package/src/services/ArchiveBulkService.test.ts +2 -2
  18. package/src/services/ClaimService.test.ts +3 -3
  19. package/src/services/ClaimService.ts +4 -4
  20. package/src/services/DoctorService.ts +24 -24
  21. package/src/services/IntegrationService.test.ts +158 -2
  22. package/src/services/IntegrationService.ts +51 -1
  23. package/src/services/ReadinessService.test.ts +1 -1
  24. package/src/services/ReviewService.test.ts +2 -2
  25. package/src/services/SyncService.test.ts +2 -2
  26. package/src/services/VcsMigrationService.test.ts +1 -1
  27. package/src/services/WorkbaseService.test.ts +33 -2
  28. package/src/services/WorkbaseService.ts +39 -3
  29. package/src/workbase/AGENTS.md +7 -7
  30. package/src/workbase/{runner-command.test.ts → agent-command.test.ts} +33 -23
  31. package/src/workbase/{runner-command.ts → agent-command.ts} +33 -29
  32. package/src/workbase/kickoff-contract.ts +4 -4
  33. package/src/workbase/opencode-file.ts +1 -1
  34. package/src/workbase/pi-extension-file.ts +158 -0
  35. package/src/workbase/schemas.test.ts +5 -5
  36. package/src/workbase/schemas.ts +8 -2
@@ -16,6 +16,10 @@ import {
16
16
  canUpdateManagedWorkbaseOpencodeTuiPlugin,
17
17
  managedWorkbaseOpencodeTuiPlugin,
18
18
  } from "../workbase/opencode-tui-plugin-file"
19
+ import {
20
+ canUpdateManagedWorkbasePiExtension,
21
+ managedWorkbasePiExtension,
22
+ } from "../workbase/pi-extension-file"
19
23
  import { IntegrationService } from "./IntegrationService"
20
24
 
21
25
  const write = async (root: string, path: string, content: string) => {
@@ -65,6 +69,7 @@ describe("IntegrationService", () => {
65
69
  "missing",
66
70
  "missing",
67
71
  "missing",
72
+ "missing",
68
73
  ])
69
74
  expect(await Bun.file(join(root, ".agency/AGENTS.md")).exists()).toBe(false)
70
75
 
@@ -81,12 +86,18 @@ describe("IntegrationService", () => {
81
86
  ".opencode/tui/agency-debug.ts",
82
87
  managedWorkbaseOpencodeTuiPlugin,
83
88
  )
89
+ await write(
90
+ root,
91
+ ".pi/extensions/agency-workbase.ts",
92
+ managedWorkbasePiExtension,
93
+ )
84
94
  expect((await status(root)).files.map(({ state }) => state)).toEqual([
85
95
  "managed",
86
96
  "managed",
87
97
  "managed",
88
98
  "managed",
89
99
  "managed",
100
+ "managed",
90
101
  ])
91
102
  })
92
103
 
@@ -104,6 +115,7 @@ describe("IntegrationService", () => {
104
115
  "missing",
105
116
  "missing",
106
117
  "missing",
118
+ "missing",
107
119
  ])
108
120
  })
109
121
 
@@ -119,7 +131,7 @@ describe("IntegrationService", () => {
119
131
  "call Herdr help, skill, or CLI discovery",
120
132
  )
121
133
  expect(managedWorkbaseAgents).toContain("exactly one final")
122
- expect(managedWorkbaseAgents).toContain("leave the runner in the")
134
+ expect(managedWorkbaseAgents).toContain("leave the agent in the")
123
135
  })
124
136
 
125
137
  test("generates a dynamic workbase plugin", () => {
@@ -208,6 +220,131 @@ describe("IntegrationService", () => {
208
220
  ).toBe(false)
209
221
  })
210
222
 
223
+ test("generates a Pi extension with workbase context and checkout skills", async () => {
224
+ expect(managedWorkbasePiExtension).toContain(
225
+ 'import { CONFIG_DIR_NAME, type ExtensionAPI } from "@earendil-works/pi-coding-agent"',
226
+ )
227
+ expect(managedWorkbasePiExtension).toContain('pi.on("resources_discover"')
228
+ expect(managedWorkbasePiExtension).toContain('pi.on("before_agent_start"')
229
+ expect(managedWorkbasePiExtension).toContain(
230
+ 'join(checkout, ".agents", "skills")',
231
+ )
232
+ expect(managedWorkbasePiExtension).toContain(
233
+ 'join(checkout, CONFIG_DIR_NAME, "skills")',
234
+ )
235
+ expect(managedWorkbasePiExtension).toContain(
236
+ "The complete Agency workbase is available",
237
+ )
238
+ expect(managedWorkbasePiExtension).toContain(
239
+ "Agency context remains the authority for writes",
240
+ )
241
+ expect(
242
+ canUpdateManagedWorkbasePiExtension(managedWorkbasePiExtension),
243
+ ).toBe(true)
244
+ expect(
245
+ canUpdateManagedWorkbasePiExtension(
246
+ managedWorkbasePiExtension.replace("resources_discover", "discover"),
247
+ ),
248
+ ).toBe(false)
249
+
250
+ const taskDirectory = join(root, "tasks/example")
251
+ const checkoutPath = join(taskDirectory, "code/agency")
252
+ await write(root, ".agency/AGENTS.md", "# Managed Agency instructions\n")
253
+ await write(
254
+ root,
255
+ "tasks/example/TASK.md",
256
+ "---\nrepo: agency\nstatus: working\n---\n",
257
+ )
258
+ await write(
259
+ root,
260
+ "tasks/example/code/agency/.agents/skills/example/SKILL.md",
261
+ "---\nname: example\ndescription: Example.\n---\n",
262
+ )
263
+ await write(
264
+ root,
265
+ "tasks/example/code/agency/.pi/skills/pi-example/SKILL.md",
266
+ "---\nname: pi-example\ndescription: Pi example.\n---\n",
267
+ )
268
+ const path = join(root, ".pi/extensions/agency-workbase.ts")
269
+ await write(
270
+ root,
271
+ ".pi/extensions/agency-workbase.ts",
272
+ managedWorkbasePiExtension.replace(
273
+ 'import { CONFIG_DIR_NAME, type ExtensionAPI } from "@earendil-works/pi-coding-agent"',
274
+ 'const CONFIG_DIR_NAME = ".pi"\ntype ExtensionAPI = any',
275
+ ),
276
+ )
277
+
278
+ const contextResponse = JSON.stringify({
279
+ version: 1,
280
+ ok: true,
281
+ result: {
282
+ workbase: { root },
283
+ target: {
284
+ kind: "task",
285
+ taskId: "example",
286
+ path: join(taskDirectory, "TASK.md"),
287
+ },
288
+ authority: {
289
+ mode: "execution",
290
+ writable: { checkoutPath },
291
+ },
292
+ documents: { task: { data: { status: "working" } } },
293
+ validation: { valid: true, warnings: [] },
294
+ },
295
+ })
296
+ const handlers = new Map<string, (...args: any[]) => any>()
297
+ const pi = {
298
+ exec: async () => ({ code: 0, stdout: contextResponse, stderr: "" }),
299
+ on: (name: string, handler: (...args: any[]) => any) => {
300
+ handlers.set(name, handler)
301
+ },
302
+ }
303
+ const previousTarget = process.env.AGENCY_TARGET
304
+ const previousWorkbase = process.env.AGENCY_WORKBASE
305
+ const previousCheckout = process.env.AGENCY_WRITABLE_CHECKOUT
306
+ delete process.env.AGENCY_WORKBASE
307
+ delete process.env.AGENCY_WRITABLE_CHECKOUT
308
+ process.env.AGENCY_TARGET = "execution-unit:task/example"
309
+ try {
310
+ const generated = await import(
311
+ `${pathToFileURL(path).href}?pi-extension=${Date.now()}`
312
+ )
313
+ generated.default(pi)
314
+ const resources = await handlers.get("resources_discover")?.({
315
+ cwd: taskDirectory,
316
+ reason: "startup",
317
+ })
318
+ expect(resources.skillPaths).toEqual([
319
+ join(checkoutPath, ".agents/skills"),
320
+ join(checkoutPath, ".pi/skills"),
321
+ ])
322
+
323
+ const prompt = await handlers.get("before_agent_start")?.(
324
+ { systemPrompt: "Base prompt" },
325
+ { cwd: taskDirectory },
326
+ )
327
+ expect(prompt.systemPrompt).toContain("# Managed Agency instructions")
328
+ expect(prompt.systemPrompt).toContain(
329
+ `The complete Agency workbase is available at ${root}`,
330
+ )
331
+ expect(prompt.systemPrompt).toContain(
332
+ "active worker for execution-unit:task/example",
333
+ )
334
+ expect(prompt.systemPrompt).toContain(
335
+ `${checkoutPath} as the default implementation directory`,
336
+ )
337
+ } finally {
338
+ if (previousTarget === undefined) delete process.env.AGENCY_TARGET
339
+ else process.env.AGENCY_TARGET = previousTarget
340
+ if (previousWorkbase === undefined) delete process.env.AGENCY_WORKBASE
341
+ else process.env.AGENCY_WORKBASE = previousWorkbase
342
+ if (previousCheckout === undefined)
343
+ delete process.env.AGENCY_WRITABLE_CHECKOUT
344
+ else process.env.AGENCY_WRITABLE_CHECKOUT = previousCheckout
345
+ }
346
+ })
347
+
211
348
  const testWorkerIdentity = async ({
212
349
  target,
213
350
  launchTarget,
@@ -640,7 +777,7 @@ describe("IntegrationService", () => {
640
777
  expect(config.agent.agency.hidden).toBeUndefined()
641
778
  expect(config.agent.agency.steps).toBeUndefined()
642
779
  expect(config.agent.agency.prompt).toContain(
643
- "verify that the runner started successfully",
780
+ "verify that the agent started successfully",
644
781
  )
645
782
  expect(config.agent.agency.prompt).toContain(
646
783
  "return without waiting for the task to finish",
@@ -733,6 +870,7 @@ describe("IntegrationService", () => {
733
870
  { name: "opencode-plugin", state: "managed", changed: true },
734
871
  { name: "opencode-tui", state: "managed", changed: true },
735
872
  { name: "opencode-tui-plugin", state: "managed", changed: true },
873
+ { name: "pi-extension", state: "managed", changed: true },
736
874
  ])
737
875
  expect(await Bun.file(join(root, "AGENTS.md")).text()).toBe(
738
876
  customRootAgents,
@@ -757,6 +895,9 @@ describe("IntegrationService", () => {
757
895
  expect(
758
896
  await Bun.file(join(root, ".opencode/tui/agency-debug.ts")).text(),
759
897
  ).toBe(managedWorkbaseOpencodeTuiPlugin)
898
+ expect(
899
+ await Bun.file(join(root, ".pi/extensions/agency-workbase.ts")).text(),
900
+ ).toBe(managedWorkbasePiExtension)
760
901
 
761
902
  await unlink(join(root, ".agency/AGENTS.md"))
762
903
  const second = await sync(root)
@@ -850,6 +991,21 @@ describe("IntegrationService", () => {
850
991
  expect(await Bun.file(legacyPath).exists()).toBe(false)
851
992
  })
852
993
 
994
+ test("preserves a user-owned Pi extension", async () => {
995
+ const custom = "export default function customPiExtension() {}\n"
996
+ await write(root, ".pi/extensions/agency-workbase.ts", custom)
997
+
998
+ const result = await sync(root)
999
+ expect(result.files[5]).toMatchObject({
1000
+ name: "pi-extension",
1001
+ state: "customized",
1002
+ changed: false,
1003
+ })
1004
+ expect(
1005
+ await Bun.file(join(root, ".pi/extensions/agency-workbase.ts")).text(),
1006
+ ).toBe(custom)
1007
+ })
1008
+
853
1009
  test("preserves user-owned TUI config and diagnostic plugin", async () => {
854
1010
  const customConfig = '{"theme":"custom"}\n'
855
1011
  const customPlugin =
@@ -23,6 +23,10 @@ import {
23
23
  canUpdateManagedWorkbaseOpencodeTuiPlugin,
24
24
  managedWorkbaseOpencodeTuiPlugin,
25
25
  } from "../workbase/opencode-tui-plugin-file"
26
+ import {
27
+ canUpdateManagedWorkbasePiExtension,
28
+ managedWorkbasePiExtension,
29
+ } from "../workbase/pi-extension-file"
26
30
 
27
31
  type IntegrationFileState = "managed" | "customized" | "missing" | "drifted"
28
32
 
@@ -33,6 +37,7 @@ interface IntegrationFileStatus {
33
37
  | "opencode-plugin"
34
38
  | "opencode-tui"
35
39
  | "opencode-tui-plugin"
40
+ | "pi-extension"
36
41
  readonly path: string
37
42
  readonly state: IntegrationFileState
38
43
  readonly diagnostic: string
@@ -131,6 +136,26 @@ const describe = (
131
136
  "Run 'agency integration sync' to install /agency-debug.",
132
137
  }
133
138
  }
139
+ if (name === "pi-extension") {
140
+ return state === "managed"
141
+ ? {
142
+ diagnostic:
143
+ "Agency's managed Pi extension provides whole-workbase context and exposes writable-checkout skills.",
144
+ remediation: null,
145
+ }
146
+ : state === "customized"
147
+ ? {
148
+ diagnostic:
149
+ "A user-owned Pi workbase extension is present and was preserved.",
150
+ remediation: null,
151
+ }
152
+ : {
153
+ diagnostic:
154
+ "The managed Pi workbase extension needs synchronization.",
155
+ remediation:
156
+ "Run 'agency integration sync' to provide workbase context and expose writable-checkout skills in Pi.",
157
+ }
158
+ }
134
159
 
135
160
  return state === "missing" || state === "drifted"
136
161
  ? {
@@ -190,6 +215,12 @@ const inspect = (root: string) =>
190
215
  "agency-repository-skills.ts",
191
216
  )
192
217
  const tuiPluginPath = join(opencodeDirectory, "tui", "agency-debug.ts")
218
+ const piExtensionPath = join(
219
+ root,
220
+ ".pi",
221
+ "extensions",
222
+ "agency-workbase.ts",
223
+ )
193
224
  const files: IntegrationFileStatus[] = []
194
225
 
195
226
  files.push(
@@ -294,6 +325,22 @@ const inspect = (root: string) =>
294
325
  files.push(fileStatus("opencode-tui-plugin", tuiPluginPath, "missing"))
295
326
  }
296
327
 
328
+ if ((yield* fs.readSymlinkTarget(piExtensionPath)) !== null) {
329
+ files.push(fileStatus("pi-extension", piExtensionPath, "customized"))
330
+ } else if (yield* fs.exists(piExtensionPath)) {
331
+ files.push(
332
+ classify(
333
+ "pi-extension",
334
+ piExtensionPath,
335
+ yield* fs.readFile(piExtensionPath),
336
+ managedWorkbasePiExtension,
337
+ canUpdateManagedWorkbasePiExtension,
338
+ ),
339
+ )
340
+ } else {
341
+ files.push(fileStatus("pi-extension", piExtensionPath, "missing"))
342
+ }
343
+
297
344
  return files
298
345
  })
299
346
 
@@ -389,12 +436,15 @@ export class IntegrationService extends Effect.Service<IntegrationService>()(
389
436
  } else if (status.name === "opencode-tui") {
390
437
  yield* fs.createDirectory(join(root, ".opencode"))
391
438
  yield* fs.writeFile(status.path, managedWorkbaseOpencodeTui)
392
- } else {
439
+ } else if (status.name === "opencode-tui-plugin") {
393
440
  yield* fs.createDirectory(join(root, ".opencode", "tui"))
394
441
  yield* fs.writeFile(
395
442
  status.path,
396
443
  managedWorkbaseOpencodeTuiPlugin,
397
444
  )
445
+ } else {
446
+ yield* fs.createDirectory(join(root, ".pi", "extensions"))
447
+ yield* fs.writeFile(status.path, managedWorkbasePiExtension)
398
448
  }
399
449
  }
400
450
  files.push({
@@ -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
  },
@@ -238,7 +238,7 @@ pr: null
238
238
  {
239
239
  taskId: "example",
240
240
  claimant: "orchestrator",
241
- runner: "agent",
241
+ agent: "agent",
242
242
  sessionId: "session-1",
243
243
  revision: inspected.revision,
244
244
  expiresAt: "2099-01-01T00:00:00.000Z",
@@ -523,7 +523,7 @@ process.stdout.write(${JSON.stringify(JSON.stringify(record))})
523
523
  {
524
524
  taskId: "finished-claim",
525
525
  claimant: "orchestrator",
526
- runner: "agent",
526
+ agent: "agent",
527
527
  sessionId: "session-1",
528
528
  revision: initial.revision,
529
529
  },
@@ -288,7 +288,7 @@ describe("VcsMigrationService", () => {
288
288
  {
289
289
  taskId: "example",
290
290
  claimant: "orchestrator",
291
- runner: "agent",
291
+ agent: "agent",
292
292
  sessionId: "session-1",
293
293
  revision: inspected.revision,
294
294
  },
@@ -41,6 +41,37 @@ describe("WorkbaseService", () => {
41
41
  ).toBe(false)
42
42
  })
43
43
 
44
+ test("loads and validates the global agent", async () => {
45
+ const configDirectory = join(root, "config")
46
+ await write(
47
+ configDirectory,
48
+ "agency/agency.json",
49
+ JSON.stringify({ agent: "pi" }),
50
+ )
51
+
52
+ const config = await runTestEffect(
53
+ WorkbaseService.pipe(
54
+ Effect.flatMap((service) => service.loadGlobalConfig(configDirectory)),
55
+ ),
56
+ )
57
+ expect(config).toEqual({ agent: "pi" })
58
+
59
+ await write(
60
+ configDirectory,
61
+ "agency/agency.json",
62
+ JSON.stringify({ agent: "codex" }),
63
+ )
64
+ await expect(
65
+ runTestEffect(
66
+ WorkbaseService.pipe(
67
+ Effect.flatMap((service) =>
68
+ service.loadGlobalConfig(configDirectory),
69
+ ),
70
+ ),
71
+ ),
72
+ ).rejects.toThrow("Invalid global Agency configuration")
73
+ })
74
+
44
75
  test("treats declared but missing repositories as valid aliases", async () => {
45
76
  await write(
46
77
  root,
@@ -415,13 +446,13 @@ status: done
415
446
  ).rejects.toThrow("Repository 'agency'")
416
447
  })
417
448
 
418
- test("rejects an unknown runner command placeholder", async () => {
449
+ test("rejects an unknown agent command placeholder", async () => {
419
450
  await write(
420
451
  root,
421
452
  "agency.json",
422
453
  JSON.stringify({
423
454
  version: 2,
424
- runners: { custom: { command: ["agent", "{unknown}"] } },
455
+ agents: { custom: { command: ["agent", "{unknown}"] } },
425
456
  }),
426
457
  )
427
458
 
@@ -8,6 +8,7 @@ import { parseFrontmatter } from "../workbase/frontmatter"
8
8
  import {
9
9
  EntityId,
10
10
  EpicFrontmatter,
11
+ GlobalConfig,
11
12
  LegacyWorkbaseRegistry,
12
13
  PhaseFrontmatter,
13
14
  TaskFrontmatter,
@@ -22,7 +23,7 @@ import {
22
23
  import { validateWorktreeCreateCommand } from "../workbase/worktree-command"
23
24
  import { validateWorkspaceCreateCommand } from "../workbase/workspace-command"
24
25
  import { validatePostCheckoutCommand } from "../workbase/checkout-command"
25
- import { validateRunners } from "../workbase/runner-command"
26
+ import { validateAgents } from "../workbase/agent-command"
26
27
  import { findDependencyCycles } from "../workbase/dependency-graph"
27
28
  import { validateDelivery } from "../workbase/delivery-command"
28
29
  import { preferredVersionControl } from "../workbase/version-control"
@@ -90,6 +91,15 @@ const registryPath = (configDirectory?: string) =>
90
91
  "workbases.json",
91
92
  )
92
93
 
94
+ const globalConfigPath = (configDirectory?: string) =>
95
+ join(
96
+ configDirectory ||
97
+ process.env.XDG_CONFIG_HOME ||
98
+ join(homedir(), ".config"),
99
+ "agency",
100
+ "agency.json",
101
+ )
102
+
93
103
  const registrationId = (path: string) =>
94
104
  `wb-${new Bun.CryptoHasher("sha256").update(path).digest("hex").slice(0, 12)}`
95
105
 
@@ -178,6 +188,32 @@ export class WorkbaseService extends Effect.Service<WorkbaseService>()(
178
188
  "WorkbaseService",
179
189
  {
180
190
  sync: () => ({
191
+ loadGlobalConfig: (configDirectory?: string) =>
192
+ Effect.gen(function* () {
193
+ const fs = yield* FileSystemService
194
+ const path = globalConfigPath(configDirectory)
195
+ if (!(yield* fs.exists(path))) return {}
196
+ const content = yield* fs.readFile(path)
197
+ let input: unknown
198
+ try {
199
+ input = JSON.parse(content)
200
+ } catch (cause) {
201
+ return yield* new WorkbaseConfigError({
202
+ path,
203
+ message: `Invalid JSON in global Agency configuration ${path}`,
204
+ cause,
205
+ })
206
+ }
207
+ const decoded = decode(GlobalConfig, input)
208
+ if (!decoded.success) {
209
+ return yield* new WorkbaseConfigError({
210
+ path,
211
+ message: `Invalid global Agency configuration in ${path}:\n${decoded.error}`,
212
+ })
213
+ }
214
+ return decoded.value
215
+ }),
216
+
181
217
  initialize: (path: string = process.cwd()) =>
182
218
  Effect.gen(function* () {
183
219
  const fs = yield* FileSystemService
@@ -309,7 +345,7 @@ export class WorkbaseService extends Effect.Service<WorkbaseService>()(
309
345
  }
310
346
  }
311
347
  try {
312
- validateRunners(decoded.value.runners)
348
+ validateAgents(decoded.value.agents)
313
349
  validateDelivery(decoded.value.delivery)
314
350
  } catch (cause) {
315
351
  return yield* new WorkbaseConfigError({
@@ -317,7 +353,7 @@ export class WorkbaseService extends Effect.Service<WorkbaseService>()(
317
353
  message:
318
354
  cause instanceof Error
319
355
  ? cause.message
320
- : "Invalid runner configuration",
356
+ : "Invalid agent configuration",
321
357
  })
322
358
  }
323
359
  return current
@@ -121,7 +121,7 @@ Do not rediscover commands that this recipe or a known-current
121
121
  prepare the task with
122
122
  `agency work prepare <slug> --evidence <creation-json> --dry-run --json`, then
123
123
  execute the returned plan through `task-document-split` to prepare the
124
- checkout and open or reuse the background tab. Stop before `runner-start`.
124
+ checkout and open or reuse the background tab. Stop before `agent-start`.
125
125
  3. For work/launch/start/kickoff intent, run that same preflight and execute its
126
126
  ordered kickoff steps. The plan owns worktree dry-run/preparation, a
127
127
  retry-safe background Herdr tab, the side-by-side task document,
@@ -131,8 +131,8 @@ Do not rediscover commands that this recipe or a known-current
131
131
  `agency-kickoff-v1` capability, execute the supplied actions directly. Do not
132
132
  call Herdr help, skill, or CLI discovery. If capability/version evidence is
133
133
  absent or stale, discovery is the compatibility path; then resume the same
134
- idempotency key rather than creating another tab, checkout, or runner.
135
- 5. After the one final context verification succeeds, leave the runner in the
134
+ idempotency key rather than creating another tab, checkout, or agent.
135
+ 5. After the one final context verification succeeds, leave the agent in the
136
136
  background and stop. Do not inspect, poll, or babysit it unless the user asks.
137
137
 
138
138
  Validation evidence is a local, auditable optimization, not authority. Preflight
@@ -153,12 +153,12 @@ IDs and remediation commands before retrying.
153
153
 
154
154
  `agency work` is the human launch flow: it reconciles managed integration,
155
155
  selects work, checks readiness, prepares checkouts, marks execution work
156
- `working` without creating a claim, and starts the runner. Epic and multi-phase
156
+ `working` without creating a claim, and starts the agent. Epic and multi-phase
157
157
  task launches remain orchestration-only. External orchestrators instead claim
158
- an execution unit, launch and monitor their runner separately, and finish or
158
+ an execution unit, launch and monitor their agent separately, and finish or
159
159
  release the claim with the current document revision.
160
160
 
161
- An Agency-launched runner receives process-local worker identity through both
161
+ An Agency-launched agent receives process-local worker identity through both
162
162
  the `AGENCY_SESSION_ID` and `AGENCY_TARGET` environment variables and a generated
163
163
  prompt beginning `Agency worker launch target: <target>.` Treat either form as
164
164
  launch evidence only after `agency context . --json` confirms the same target,
@@ -166,7 +166,7 @@ document paths, valid context, and expected write authority. Once confirmed,
166
166
  perform the assigned work directly and never invoke `agency work` to start the
167
167
  same target again.
168
168
 
169
- Some runner clients attach to a long-lived process and may not preserve launch
169
+ Some agent clients attach to a long-lived process and may not preserve launch
170
170
  environment variables. If the variables and prompt marker are absent, fail safe
171
171
  when the initial instruction is a generated `Start`, `Continue`, or `Work on`
172
172
  prompt whose absolute document paths match the current directory and the active,