@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
package/README.md CHANGED
@@ -11,7 +11,7 @@ read or write.
11
11
  - Git
12
12
  - [Jujutsu](https://jj-vcs.github.io/jj/) is preferred when available
13
13
  - [GitHub CLI](https://cli.github.com/) for `agency pr`
14
- - OpenCode, Claude Code, or a configured runner for `agency work`
14
+ - OpenCode, Claude Code, or a configured agent for `agency work`
15
15
 
16
16
  ## Installation
17
17
 
@@ -56,6 +56,8 @@ workbase/
56
56
  tui.jsonc # managed TUI plugin registration
57
57
  plugins/agency-repository-skills.ts # managed workbase access and checkout skills
58
58
  tui/agency-debug.ts # managed /agency-debug TUI diagnostic
59
+ .pi/
60
+ extensions/agency-workbase.ts # managed workbase context and checkout skills
59
61
  agency.json # tracked config and portable repository declarations
60
62
  repos/ # ignored local materializations
61
63
  frontend/ # bare Git repository or symlink
@@ -83,11 +85,11 @@ workbase/
83
85
  ```
84
86
 
85
87
  Agency keeps discovery and other observational commands read-only. Run
86
- `agency integration status` to inspect `.agency/AGENTS.md` and
87
- `.opencode/opencode.jsonc`, `.opencode/tui.jsonc`, and their managed plugin
88
- files, then `agency integration sync` to create missing files or refresh
89
- checksum-safe managed files. Customized files are reported but never
90
- overwritten. Sync also removes checksum-valid retired managed artifacts while
88
+ `agency integration status` to inspect `.agency/AGENTS.md`, the managed
89
+ OpenCode configuration and plugins, and `.pi/extensions/agency-workbase.ts`,
90
+ then `agency integration sync` to create missing files or refresh checksum-safe
91
+ managed files. Customized files are reported but never overwritten. Sync also
92
+ removes checksum-valid retired managed artifacts while
91
93
  preserving customized files at their former paths. The root
92
94
  `AGENTS.md` is user-owned and is not inspected or modified by Agency.
93
95
 
@@ -111,7 +113,7 @@ read-only Agency commands, and use explicit Agency CLI permissions to create or
111
113
  update planning structure. Its normal research tools and the complete Agency CLI
112
114
  remain available; managed Agency instructions and reported authority govern each
113
115
  operation.
114
- When the subagent launches work in another agent, it verifies that the runner
116
+ When the subagent launches work in another agent, it verifies that the agent
115
117
  started and returns without waiting for the task to finish.
116
118
  The TUI-only `/agency-debug` command reports TUI companion initialization and
117
119
  whether the server plugin registered writable-checkout skills. It uses a native
@@ -126,6 +128,16 @@ The plugin grants whole-workbase access dynamically, while the portable
126
128
  reference advertises that context to agents. Bash and Agency operations must
127
129
  still follow the write authority reported by `agency context`.
128
130
 
131
+ Pi discovers the managed project extension automatically when launched from
132
+ the workbase root after the project is trusted. When launching Pi from a task,
133
+ phase, or epic directory, pass the managed file with `--extension`, for example
134
+ `pi -e /path/to/workbase/.pi/extensions/agency-workbase.ts`. The extension loads
135
+ the managed Agency instructions into Pi's system prompt, advertises the complete
136
+ workbase, and exposes skills from the writable checkout's `.claude/skills`,
137
+ `.agents/skills`, `.opencode/{skill,skills}`, and `.pi/skills` directories.
138
+ Agency context still determines write authority; reference checkouts remain
139
+ read-only.
140
+
129
141
  Repository aliases, the version-control backend, and canonical fetch remotes are
130
142
  declared in tracked `agency.json`; local clones and symlinks remain ignored under
131
143
  `repos/{alias}`. A declaration contains no local path, symlink target, checkout,
@@ -348,23 +360,36 @@ retries checkout creation and the hook rather than reusing an uninitialized
348
360
  checkout. Hook commands should be idempotent so a retry is safe after any
349
361
  external effects the failed invocation may have completed.
350
362
 
351
- ### Agent Runners
363
+ ### Agents
364
+
365
+ OpenCode (`opencode2` and `opencode`), Pi, and Claude Code are built-in agent presets.
366
+ Without an explicit agent, Agency uses the first available executable in this
367
+ order: `opencode2`, `opencode`, `pi`, then `claude`. Select a preset or configured
368
+ agent with `agency work --agent <name>`. To select a built-in agent globally,
369
+ set `agent` in `$XDG_CONFIG_HOME/agency/agency.json` (or
370
+ `~/.config/agency/agency.json`):
371
+
372
+ ```json
373
+ {
374
+ "agent": "pi"
375
+ }
376
+ ```
352
377
 
353
- OpenCode (`opencode2` and `opencode`) and Claude Code are built-in runner presets.
354
- Without an explicit runner, Agency uses the first available executable in this
355
- order: `opencode2`, `opencode`, then `claude`. Select a preset or configured
356
- runner with `agency work --runner <name>`. A launch is fresh unless
357
- `AGENCY_SESSION_ID` is already set; resumed launches use the runner's
378
+ The selection precedence is `--agent` (including the legacy `--opencode` and
379
+ `--claude` aliases), then `AGENCY_AGENT`, then `agent`, then automatic
380
+ detection. Supported global values are `opencode2`, `opencode`, `pi`, and
381
+ `claude`; an unavailable configured agent fails rather than falling back. A launch
382
+ is fresh unless `AGENCY_SESSION_ID` is already set; resumed launches use the agent's
358
383
  `resumeCommand` when configured. The built-in presets use `--continue` only for
359
- resumed launches. By default Agency opens the runner without a prompt. `--auto`
384
+ resumed launches. By default Agency opens the agent without a prompt. `--auto`
360
385
  uses its autonomous command and sends the generated task, phase, or epic prompt.
361
386
 
362
- Custom runners are direct argv commands, never shell snippets:
387
+ Custom agents are direct argv commands, never shell snippets:
363
388
 
364
389
  ```json
365
390
  {
366
391
  "version": 2,
367
- "runners": {
392
+ "agents": {
368
393
  "custom": {
369
394
  "command": ["my-agent"],
370
395
  "autoCommand": ["my-agent", "--prompt", "{prompt}"],
@@ -381,19 +406,19 @@ Available placeholders are `{prompt}`, `{workbase}`, `{target}`, `{task}`,
381
406
  placeholders are empty when they do not apply. `{prompt}` is empty unless
382
407
  `--auto` is set. If `resumeCommand` is omitted, the fresh command is also used
383
408
  for resumed sessions. If `autoResumeCommand` is omitted, `autoCommand` is used;
384
- configured runners without `autoCommand` reject `--auto`.
409
+ configured agents without `autoCommand` reject `--auto`.
385
410
 
386
- Every runner receives the same `AGENCY_RUNNER`, `AGENCY_CLAIMANT`,
411
+ Every agent receives the same `AGENCY_AGENT`, `AGENCY_CLAIMANT`,
387
412
  `AGENCY_SESSION_ID`, `AGENCY_CLAIM_REVISION`, `AGENCY_WORKBASE`, `AGENCY_TARGET`,
388
413
  `AGENCY_TASK_ID`, `AGENCY_PHASE_ID`, and `AGENCY_PROMPT` environment. Configured
389
414
  environment is added without overriding these normalized values.
390
- Execution-unit runners also receive `AGENCY_WRITABLE_CHECKOUT` with the
415
+ Execution-unit agents also receive `AGENCY_WRITABLE_CHECKOUT` with the
391
416
  authoritative writable checkout path.
392
417
  `AGENCY_CLAIM_REVISION` is empty for local `agency work` launches.
393
418
  `AGENCY_PROMPT` is empty unless `--auto` is set.
394
419
  Autonomous prompts begin `Agency worker launch target: <target>.`, carrying the
395
420
  same canonical target as `AGENCY_TARGET`. This is the process-local fallback for
396
- runner clients that attach to a long-lived process and lose launch environment
421
+ agent clients that attach to a long-lived process and lose launch environment
397
422
  variables. A worker must verify either signal against `agency context . --json`
398
423
  before acting; a matching worker performs the task directly and must not invoke
399
424
  `agency work` for the same target. Managed guidance also fails safe for older
@@ -404,18 +429,21 @@ to the receiving OpenCode session, injects an explicit active-worker system
404
429
  instruction, and restores Agency identity for that session's shell environment.
405
430
  This session bridge is necessary because an OpenCode client can attach to a
406
431
  long-lived server process that did not inherit the client's launch environment.
407
- The `opencode2` and `opencode` runners remain rooted in their task or epic
432
+ The `opencode2` and `opencode` agents remain rooted in their task or epic
408
433
  working directory so the workbase `AGENTS.md` and managed OpenCode config are
409
434
  discovered normally.
410
435
  Agency's managed OpenCode plugin grants the active workbase external-directory
411
436
  access and adds existing checkout-local `.claude/skills`, `.agents/skills`, and
412
- `.opencode/{skill,skills}` directories to `skills.paths`.
413
- `agency work` supplies the checkout directly; plain OpenCode launches resolve a
414
- materialized execution-unit checkout through `agency context`. A multi-phase
437
+ `.opencode/{skill,skills}` directories to `skills.paths`. The managed Pi
438
+ extension provides equivalent whole-workbase context and additionally discovers
439
+ checkout-local `.pi/skills` through Pi's `resources_discover` lifecycle.
440
+ `agency work` supplies the checkout directly; plain OpenCode launches and Pi
441
+ launches with the managed extension loaded resolve a materialized execution-unit
442
+ checkout through `agency context`. A multi-phase
415
443
  task root has no single checkout, so launch from its phase directory when using
416
- plain OpenCode. Other checkout-local configuration is not composed.
444
+ plain OpenCode or Pi. Other checkout-local configuration is not composed.
417
445
  `--print-command` prints the exact cwd and argv plus non-secret environment keys
418
- without launching the runner.
446
+ without launching the agent.
419
447
 
420
448
  ### Custom Chooser Command
421
449
 
@@ -776,7 +804,7 @@ agency task new [id] [--work [--auto]]
776
804
  ```
777
805
 
778
806
  `--work` starts work on the newly created entity. Add `--auto` to pass the
779
- generated context prompt to the selected runner. These launch options are also
807
+ generated context prompt to the selected agent. These launch options are also
780
808
  available on `epic new` and `phase new`; they cannot be combined with `--json`.
781
809
 
782
810
  Create a single-phase task:
@@ -976,7 +1004,7 @@ outcome.
976
1004
 
977
1005
  `delegated` remains readable for existing workbases but cannot be newly assigned.
978
1006
  Delegation is now explicit: the claimant identifies the orchestrator and the
979
- runner identifies the assigned agent.
1007
+ agent identifies the assigned agent.
980
1008
 
981
1009
  Human list output is a compact table with lifecycle, readiness, parent,
982
1010
  repository, branch, recorded PR, and worktree state where applicable. List and
@@ -992,7 +1020,7 @@ Claim mutations require the SHA-256 revision exposed by `agency context` or
992
1020
  document lock and atomically replaces the execution document.
993
1021
 
994
1022
  ```text
995
- agency claim <task-id> [phase-id] --claimant <id> --runner <id>
1023
+ agency claim <task-id> [phase-id] --claimant <id> --agent <id>
996
1024
  --session-id <id> --revision <sha256> [--expires-at <timestamp>] [--json]
997
1025
  agency release <task-id> [phase-id] --session-id <id>
998
1026
  --revision <sha256> [--json]
@@ -1012,8 +1040,8 @@ rather than overwriting it. Expired claims may be replaced with a
1012
1040
  revision-guarded claim.
1013
1041
 
1014
1042
  `agency work` does not claim execution units. It refuses active explicit claims,
1015
- marks open execution work `working`, and launches the runner. External
1016
- orchestrators use `agency claim`, launch and monitor their runner separately, and
1043
+ marks open execution work `working`, and launches the agent. External
1044
+ orchestrators use `agency claim`, launch and monitor their agent separately, and
1017
1045
  later call `agency release` or `agency finish`.
1018
1046
 
1019
1047
  ### Archive
@@ -1056,7 +1084,7 @@ until restored.
1056
1084
  ### Work, Publication, and Pull Requests
1057
1085
 
1058
1086
  ```text
1059
- agency work [<directory> | --epic <epic-id>] [--runner <name>] [--auto] [--print-command]
1087
+ agency work [<directory> | --epic <epic-id>] [--agent <name>] [--auto] [--print-command]
1060
1088
  agency work prepare [target] [--evidence <json-or-path>] [--dry-run] [--json]
1061
1089
  agency worktree <list|inspect|prepare|remove|rebuild|repair>
1062
1090
  agency push [--json]
@@ -1069,7 +1097,7 @@ configured external chooser. Pass a directory, including `.` for the current
1069
1097
  directory, to infer its epic, task, or phase. Outside a workbase, Agency first
1070
1098
  presents the registered workbases, then the selected workbase's hierarchy.
1071
1099
 
1072
- Agency automatically uses the first available runner in this order: `opencode2`,
1100
+ Agency automatically uses the first available agent in this order: `opencode2`,
1073
1101
  `opencode`, then `claude`. `--opencode` and `--claude` remain aliases for
1074
1102
  requiring their corresponding built-in presets. Launches are interactive and
1075
1103
  promptless by default; use `--auto` to send Agency's generated context prompt.
package/cli-main.ts CHANGED
@@ -206,7 +206,7 @@ const commands: Record<string, Command> = {
206
206
  taskId: args[0],
207
207
  phaseId: args[1],
208
208
  claimant: options.claimant,
209
- runner: options.runner,
209
+ agent: options.agent,
210
210
  sessionId: options["session-id"],
211
211
  revision: options.revision,
212
212
  expiresAt: options["expires-at"],
@@ -584,7 +584,7 @@ const commands: Record<string, Command> = {
584
584
  verbose: options.verbose,
585
585
  opencode: options.opencode,
586
586
  claude: options.claude,
587
- runner: options.runner,
587
+ agent: options.agent,
588
588
  auto: options.auto,
589
589
  printCommand: options["print-command"],
590
590
  force: options.force,
@@ -28,7 +28,7 @@
28
28
  "ui",
29
29
  "--claimant",
30
30
  "orchestrator-1",
31
- "--runner",
31
+ "--agent",
32
32
  "opencode",
33
33
  "--session-id",
34
34
  "session-123",
@@ -47,7 +47,7 @@
47
47
  "--json"
48
48
  ],
49
49
  ["work", "prepare", "--task", "checkout", "--phase", "ui", "--json"],
50
- ["work", "tasks/checkout/phases/ui", "--runner", "opencode"],
50
+ ["work", "tasks/checkout/phases/ui", "--agent", "opencode"],
51
51
  ["sync", "--dry-run", "--json"],
52
52
  ["sync", "--json"],
53
53
  ["pr", "create", "checkout", "ui", "--json"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markjaquith/agency",
3
- "version": "2.67.0",
3
+ "version": "2.69.0",
4
4
  "description": "Manage agentic work across repositories with durable workbases",
5
5
  "keywords": [
6
6
  "agents",
@@ -539,7 +539,7 @@
539
539
  "additionalProperties": false,
540
540
  "required": [
541
541
  "claimant",
542
- "runner",
542
+ "agent",
543
543
  "sessionId",
544
544
  "startedAt",
545
545
  "targetRevision",
@@ -547,7 +547,7 @@
547
547
  ],
548
548
  "properties": {
549
549
  "claimant": { "type": "string", "minLength": 1 },
550
- "runner": { "type": "string", "minLength": 1 },
550
+ "agent": { "type": "string", "minLength": 1 },
551
551
  "sessionId": { "type": "string", "minLength": 1 },
552
552
  "startedAt": { "type": "string", "format": "date-time" },
553
553
  "targetRevision": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
@@ -343,7 +343,7 @@ describe("strict CLI parsing", () => {
343
343
  "three",
344
344
  "--claimant",
345
345
  "a",
346
- "--runner",
346
+ "--agent",
347
347
  "r",
348
348
  "--session-id",
349
349
  "s",
@@ -499,7 +499,7 @@ describe("strict CLI parsing", () => {
499
499
  "phase",
500
500
  "--claimant",
501
501
  "orchestrator",
502
- "--runner",
502
+ "--agent",
503
503
  "agent",
504
504
  "--session-id",
505
505
  "job-1",
@@ -699,12 +699,12 @@ describe("strict CLI parsing", () => {
699
699
  expectUsageError(["push", "example"], "agency push")
700
700
  })
701
701
 
702
- test("accepts runner selection and command inspection for work", () => {
702
+ test("accepts agent selection and command inspection for work", () => {
703
703
  expect(
704
704
  parseCli([
705
705
  "work",
706
706
  "example",
707
- "--runner",
707
+ "--agent",
708
708
  "custom",
709
709
  "--auto",
710
710
  "--print-command",
@@ -712,10 +712,10 @@ describe("strict CLI parsing", () => {
712
712
  ).toMatchObject({
713
713
  commandName: "work",
714
714
  args: ["example"],
715
- values: { runner: "custom", auto: true, "print-command": true },
715
+ values: { agent: "custom", auto: true, "print-command": true },
716
716
  })
717
717
  expect(() =>
718
- parseCli(["work", "example", "--runner", "custom", "--claude"]),
718
+ parseCli(["work", "example", "--agent", "custom", "--claude"]),
719
719
  ).toThrow("cannot be combined")
720
720
  expect(() => parseCli(["work", "prepare", "--print-command"])).toThrow(
721
721
  "cannot be combined",
@@ -989,7 +989,7 @@ describe("strict CLI parsing", () => {
989
989
  "release",
990
990
  "--claimant",
991
991
  "agent",
992
- "--runner",
992
+ "--agent",
993
993
  "opencode",
994
994
  "--session-id",
995
995
  "session",
package/src/cli-parser.ts CHANGED
@@ -117,7 +117,7 @@ const mutationOptions = {
117
117
  const claimOptions = {
118
118
  ...outputOptions,
119
119
  claimant: { type: "string" },
120
- runner: { type: "string" },
120
+ agent: { type: "string" },
121
121
  "session-id": { type: "string" },
122
122
  revision: { type: "string" },
123
123
  "expires-at": { type: "string" },
@@ -671,12 +671,12 @@ const commands = {
671
671
  },
672
672
  command: {
673
673
  usage:
674
- "agency claim <task-id> [phase-id] --claimant <id> --runner <id> --session-id <id> --revision <sha256> [--expires-at <timestamp>] [--json]",
674
+ "agency claim <task-id> [phase-id] --claimant <id> --agent <id> --session-id <id> --revision <sha256> [--expires-at <timestamp>] [--json]",
675
675
  minArgs: 1,
676
676
  maxArgs: 2,
677
677
  options: [
678
678
  "claimant",
679
- "runner",
679
+ "agent",
680
680
  "session-id",
681
681
  "revision",
682
682
  "expires-at",
@@ -684,7 +684,7 @@ const commands = {
684
684
  "task",
685
685
  "phase",
686
686
  ],
687
- required: ["claimant", "runner", "session-id", "revision"],
687
+ required: ["claimant", "agent", "session-id", "revision"],
688
688
  },
689
689
  },
690
690
  release: {
@@ -916,13 +916,13 @@ const commands = {
916
916
  },
917
917
  work: {
918
918
  usage:
919
- "agency work [<directory-or-task-id> | --epic <epic-id>] [--runner <name>] [--auto] | agency work prepare [target] [--dry-run] [--json]",
919
+ "agency work [<directory-or-task-id> | --epic <epic-id>] [--agent <name>] [--auto] | agency work prepare [target] [--dry-run] [--json]",
920
920
  options: {
921
921
  ...commonOptions,
922
922
  ...entitySelectorOptions,
923
923
  json: { type: "boolean" },
924
924
  "dry-run": { type: "boolean" },
925
- runner: { type: "string" },
925
+ agent: { type: "string" },
926
926
  auto: { type: "boolean" },
927
927
  "print-command": { type: "boolean" },
928
928
  opencode: { type: "boolean" },
@@ -932,7 +932,7 @@ const commands = {
932
932
  },
933
933
  command: {
934
934
  usage:
935
- "agency work [<directory-or-task-id> | --epic <epic-id>] [--runner <name>] [--auto] | agency work prepare [target] [--dry-run] [--json]",
935
+ "agency work [<directory-or-task-id> | --epic <epic-id>] [--agent <name>] [--auto] | agency work prepare [target] [--dry-run] [--json]",
936
936
  minArgs: 0,
937
937
  maxArgs: 2,
938
938
  options: [
@@ -941,7 +941,7 @@ const commands = {
941
941
  "epic",
942
942
  "task",
943
943
  "phase",
944
- "runner",
944
+ "agent",
945
945
  "auto",
946
946
  "print-command",
947
947
  "opencode",
@@ -951,8 +951,8 @@ const commands = {
951
951
  ],
952
952
  conflicts: [
953
953
  ["opencode", "claude"],
954
- ["runner", "opencode"],
955
- ["runner", "claude"],
954
+ ["agent", "opencode"],
955
+ ["agent", "claude"],
956
956
  ["epic", "$positional"],
957
957
  ],
958
958
  },
@@ -1689,7 +1689,7 @@ export function parseCli(args: readonly string[]): ParsedCli {
1689
1689
  (parsed.values.epic ||
1690
1690
  parsed.values.opencode ||
1691
1691
  parsed.values.claude ||
1692
- parsed.values.runner ||
1692
+ parsed.values.agent ||
1693
1693
  parsed.values.auto ||
1694
1694
  parsed.values["print-command"] ||
1695
1695
  parsed.values.force))
package/src/cli.test.ts CHANGED
@@ -192,7 +192,7 @@ describe("CLI", () => {
192
192
  "claimed",
193
193
  "--claimant",
194
194
  "orchestrator",
195
- "--runner",
195
+ "--agent",
196
196
  "agent",
197
197
  "--session-id",
198
198
  "job-1",
@@ -205,7 +205,7 @@ describe("CLI", () => {
205
205
  )
206
206
  expect(claimed.claim).toMatchObject({
207
207
  claimant: "orchestrator",
208
- runner: "agent",
208
+ agent: "agent",
209
209
  sessionId: "job-1",
210
210
  state: "active",
211
211
  })
@@ -216,7 +216,7 @@ describe("CLI", () => {
216
216
  "claimed",
217
217
  "--claimant",
218
218
  "other",
219
- "--runner",
219
+ "--agent",
220
220
  "other-agent",
221
221
  "--session-id",
222
222
  "job-2",
@@ -232,7 +232,7 @@ describe("CLI", () => {
232
232
  error: {
233
233
  code: "CLAIM_CONFLICT",
234
234
  retryable: true,
235
- fields: { claim: { runner: "agent", sessionId: "job-1" } },
235
+ fields: { claim: { agent: "agent", sessionId: "job-1" } },
236
236
  },
237
237
  })
238
238
 
@@ -274,7 +274,7 @@ describe("CLI", () => {
274
274
  "non-pr",
275
275
  "--claimant",
276
276
  "orchestrator",
277
- "--runner",
277
+ "--agent",
278
278
  "agent",
279
279
  "--session-id",
280
280
  "job-2",
@@ -642,6 +642,7 @@ exit 23
642
642
  { name: "opencode-plugin", state: "managed" },
643
643
  { name: "opencode-tui", state: "managed" },
644
644
  { name: "opencode-tui-plugin", state: "managed" },
645
+ { name: "pi-extension", state: "managed" },
645
646
  ])
646
647
 
647
648
  const synced = parseJson(
@@ -653,6 +654,7 @@ exit 23
653
654
  { name: "opencode-plugin", state: "managed", changed: false },
654
655
  { name: "opencode-tui", state: "managed", changed: false },
655
656
  { name: "opencode-tui-plugin", state: "managed", changed: false },
657
+ { name: "pi-extension", state: "managed", changed: false },
656
658
  ])
657
659
  })
658
660
 
@@ -1012,7 +1014,7 @@ status: open
1012
1014
  `${JSON.stringify(
1013
1015
  {
1014
1016
  ...agencyConfig,
1015
- runners: { noop: { command: ["true"] } },
1017
+ agents: { noop: { command: ["true"] } },
1016
1018
  },
1017
1019
  null,
1018
1020
  2,
@@ -1419,7 +1421,7 @@ status: open
1419
1421
  await runCli(["task", "status", "example", "dropped", "--json"], root),
1420
1422
  )
1421
1423
  const blocked = await runCli(
1422
- ["work", "--task", "example", "--runner", "noop"],
1424
+ ["work", "--task", "example", "--agent", "noop"],
1423
1425
  root,
1424
1426
  )
1425
1427
  expect(blocked.exitCode).toBe(1)
@@ -1430,7 +1432,7 @@ status: open
1430
1432
  ).toBe("dropped")
1431
1433
 
1432
1434
  const resumedTask = await runCli(
1433
- ["work", "--task", "example", "--runner", "noop", "--force"],
1435
+ ["work", "--task", "example", "--agent", "noop", "--force"],
1434
1436
  root,
1435
1437
  )
1436
1438
  expect(resumedTask).toMatchObject({ exitCode: 0, stderr: "" })
@@ -1455,7 +1457,7 @@ status: open
1455
1457
  "pipeline",
1456
1458
  "--phase",
1457
1459
  "build",
1458
- "--runner",
1460
+ "--agent",
1459
1461
  "noop",
1460
1462
  "--force",
1461
1463
  ],
@@ -8,7 +8,7 @@ interface ClaimCommandOptions extends BaseCommandOptions {
8
8
  readonly taskId?: string
9
9
  readonly phaseId?: string
10
10
  readonly claimant?: string
11
- readonly runner?: string
11
+ readonly agent?: string
12
12
  readonly sessionId?: string
13
13
  readonly revision?: string
14
14
  readonly expiresAt?: string
@@ -29,10 +29,10 @@ export const claimCommand = (options: ClaimCommandOptions) =>
29
29
  }
30
30
  if (
31
31
  options.operation === "claim" &&
32
- (!options.claimant || !options.runner)
32
+ (!options.claimant || !options.agent)
33
33
  ) {
34
34
  return yield* Effect.fail(
35
- new Error("Claimant and runner identities are required"),
35
+ new Error("Claimant and agent identities are required"),
36
36
  )
37
37
  }
38
38
  if (options.noPullRequest && !options.summary?.trim()) {
@@ -67,7 +67,7 @@ export const claimCommand = (options: ClaimCommandOptions) =>
67
67
  {
68
68
  ...common,
69
69
  claimant: options.claimant!,
70
- runner: options.runner!,
70
+ agent: options.agent!,
71
71
  ...(options.expiresAt ? { expiresAt: options.expiresAt } : {}),
72
72
  },
73
73
  cwd,
@@ -101,9 +101,9 @@ export const claimCommand = (options: ClaimCommandOptions) =>
101
101
  })
102
102
 
103
103
  export const claimHelp = `
104
- Usage: agency claim <task-id> [phase-id] --claimant <id> --runner <id> --session-id <id> --revision <sha256>
104
+ Usage: agency claim <task-id> [phase-id] --claimant <id> --agent <id> --session-id <id> --revision <sha256>
105
105
 
106
- Claim an execution unit. Use distinct claimant and runner identities for delegated
106
+ Claim an execution unit. Use distinct claimant and agent identities for delegated
107
107
  work. --expires-at accepts an optional future ISO-8601 timestamp.
108
108
  `
109
109
 
@@ -39,7 +39,7 @@ describe("doctor command", () => {
39
39
  "agency.json",
40
40
  JSON.stringify({
41
41
  version: 2,
42
- runners: {
42
+ agents: {
43
43
  missing: {
44
44
  command: ["definitely-not-installed"],
45
45
  autoCommand: ["also-not-installed", "{prompt}"],
@@ -87,12 +87,12 @@ status: open
87
87
  status: "pass",
88
88
  }),
89
89
  expect.objectContaining({
90
- id: "integration.runner.missing",
90
+ id: "integration.agent.missing",
91
91
  level: "error",
92
92
  status: "fail",
93
93
  }),
94
94
  expect.objectContaining({
95
- id: "integration.runner.missing.auto",
95
+ id: "integration.agent.missing.auto",
96
96
  level: "error",
97
97
  status: "fail",
98
98
  }),
@@ -89,6 +89,12 @@ describe("init command", () => {
89
89
  expect(tuiPlugin).toContain('slashName: "agency-debug"')
90
90
  expect(tuiPlugin).toContain("api.ui.toast")
91
91
  expect(tuiPlugin).not.toContain("chat.message")
92
+ const piExtension = await Bun.file(
93
+ join(root, ".pi/extensions/agency-workbase.ts"),
94
+ ).text()
95
+ expect(piExtension).toContain('pi.on("resources_discover"')
96
+ expect(piExtension).toContain('pi.on("before_agent_start"')
97
+ expect(piExtension).toContain("AGENCY_WRITABLE_CHECKOUT")
92
98
  })
93
99
 
94
100
  test("preserves existing gitignore entries", async () => {
@@ -51,6 +51,11 @@ describe("integration command", () => {
51
51
  state: "missing",
52
52
  remediation: expect.stringContaining("integration sync"),
53
53
  },
54
+ {
55
+ name: "pi-extension",
56
+ state: "missing",
57
+ remediation: expect.stringContaining("integration sync"),
58
+ },
54
59
  ],
55
60
  })
56
61
  })
@@ -99,7 +104,12 @@ OpenCode TUI config: missing
99
104
  OpenCode /agency-debug: missing
100
105
  Path: .opencode/tui/agency-debug.ts
101
106
  The managed OpenCode TUI diagnostic companion needs synchronization.
102
- Action: Run 'agency integration sync' to install /agency-debug.`)
107
+ Action: Run 'agency integration sync' to install /agency-debug.
108
+
109
+ Pi workbase extension: missing
110
+ Path: .pi/extensions/agency-workbase.ts
111
+ The managed Pi workbase extension needs synchronization.
112
+ Action: Run 'agency integration sync' to provide workbase context and expose writable-checkout skills in Pi.`)
103
113
  })
104
114
 
105
115
  test("explicitly synchronizes integration files", async () => {
@@ -113,6 +123,7 @@ OpenCode /agency-debug: missing
113
123
  { name: "opencode-plugin", state: "managed", changed: true },
114
124
  { name: "opencode-tui", state: "managed", changed: true },
115
125
  { name: "opencode-tui-plugin", state: "managed", changed: true },
126
+ { name: "pi-extension", state: "managed", changed: true },
116
127
  ])
117
128
  expect(await Bun.file(join(root, "AGENTS.md")).exists()).toBe(false)
118
129
  expect(await Bun.file(join(root, ".agency/AGENTS.md")).exists()).toBe(true)
@@ -133,6 +144,9 @@ OpenCode /agency-debug: missing
133
144
  expect(
134
145
  await Bun.file(join(root, ".opencode/tui/agency-debug.ts")).exists(),
135
146
  ).toBe(true)
147
+ expect(
148
+ await Bun.file(join(root, ".pi/extensions/agency-workbase.ts")).exists(),
149
+ ).toBe(true)
136
150
  })
137
151
 
138
152
  test("formats integration sync results for people", async () => {
@@ -160,6 +174,10 @@ OpenCode TUI config: synced
160
174
 
161
175
  OpenCode /agency-debug: synced
162
176
  Path: .opencode/tui/agency-debug.ts
163
- Agency's managed OpenCode TUI diagnostic companion is current.`)
177
+ Agency's managed OpenCode TUI diagnostic companion is current.
178
+
179
+ Pi workbase extension: synced
180
+ Path: .pi/extensions/agency-workbase.ts
181
+ Agency's managed Pi extension provides whole-workbase context and exposes writable-checkout skills.`)
164
182
  })
165
183
  })