subharness 0.0.4 → 0.0.5

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 (188) hide show
  1. package/README.md +36 -6
  2. package/dist/adapters/claude-process.d.ts +3 -0
  3. package/dist/adapters/claude-process.js +11 -1
  4. package/dist/adapters/claude-process.js.map +1 -1
  5. package/dist/adapters/claude-result.d.ts +2 -0
  6. package/dist/adapters/claude-result.js +22 -0
  7. package/dist/adapters/claude-result.js.map +1 -0
  8. package/dist/adapters/claude.js +30 -11
  9. package/dist/adapters/claude.js.map +1 -1
  10. package/dist/adapters/codex.js +4 -1
  11. package/dist/adapters/codex.js.map +1 -1
  12. package/dist/adapters/copilot-permissions.d.ts +26 -0
  13. package/dist/adapters/copilot-permissions.js +121 -0
  14. package/dist/adapters/copilot-permissions.js.map +1 -0
  15. package/dist/adapters/copilot-tools.d.ts +12 -0
  16. package/dist/adapters/copilot-tools.js +61 -0
  17. package/dist/adapters/copilot-tools.js.map +1 -0
  18. package/dist/adapters/copilot.d.ts +108 -0
  19. package/dist/adapters/copilot.js +819 -0
  20. package/dist/adapters/copilot.js.map +1 -0
  21. package/dist/adapters/cursor-cli-approvals.d.ts +2 -0
  22. package/dist/adapters/cursor-cli-approvals.js +83 -0
  23. package/dist/adapters/cursor-cli-approvals.js.map +1 -0
  24. package/dist/adapters/cursor-cli-model.d.ts +4 -0
  25. package/dist/adapters/cursor-cli-model.js +64 -0
  26. package/dist/adapters/cursor-cli-model.js.map +1 -0
  27. package/dist/adapters/cursor-cli-session.d.ts +32 -0
  28. package/dist/adapters/cursor-cli-session.js +316 -0
  29. package/dist/adapters/cursor-cli-session.js.map +1 -0
  30. package/dist/adapters/cursor-cli-tools.d.ts +20 -0
  31. package/dist/adapters/cursor-cli-tools.js +181 -0
  32. package/dist/adapters/cursor-cli-tools.js.map +1 -0
  33. package/dist/adapters/cursor-cli.d.ts +2 -0
  34. package/dist/adapters/cursor-cli.js +306 -0
  35. package/dist/adapters/cursor-cli.js.map +1 -0
  36. package/dist/adapters/cursor-model.d.ts +7 -0
  37. package/dist/adapters/cursor-model.js +67 -0
  38. package/dist/adapters/cursor-model.js.map +1 -0
  39. package/dist/adapters/cursor-rpc.d.ts +42 -0
  40. package/dist/adapters/cursor-rpc.js +271 -0
  41. package/dist/adapters/cursor-rpc.js.map +1 -0
  42. package/dist/adapters/cursor-session.d.ts +4 -0
  43. package/dist/adapters/cursor-session.js +327 -0
  44. package/dist/adapters/cursor-session.js.map +1 -0
  45. package/dist/adapters/cursor-startup.d.ts +16 -0
  46. package/dist/adapters/cursor-startup.js +74 -0
  47. package/dist/adapters/cursor-startup.js.map +1 -0
  48. package/dist/adapters/cursor-tools.d.ts +11 -0
  49. package/dist/adapters/cursor-tools.js +49 -0
  50. package/dist/adapters/cursor-tools.js.map +1 -0
  51. package/dist/adapters/cursor.d.ts +6 -0
  52. package/dist/adapters/cursor.js +17 -0
  53. package/dist/adapters/cursor.js.map +1 -0
  54. package/dist/adapters/fx-auth.d.ts +12 -2
  55. package/dist/adapters/fx-auth.js +51 -61
  56. package/dist/adapters/fx-auth.js.map +1 -1
  57. package/dist/adapters/fx-profile.d.ts +8 -0
  58. package/dist/adapters/fx-profile.js +101 -0
  59. package/dist/adapters/fx-profile.js.map +1 -0
  60. package/dist/adapters/fx-rpc.d.ts +2 -0
  61. package/dist/adapters/fx-rpc.js +30 -4
  62. package/dist/adapters/fx-rpc.js.map +1 -1
  63. package/dist/adapters/fx-status.d.ts +2 -0
  64. package/dist/adapters/fx-status.js +96 -0
  65. package/dist/adapters/fx-status.js.map +1 -0
  66. package/dist/adapters/fx.js +28 -12
  67. package/dist/adapters/fx.js.map +1 -1
  68. package/dist/adapters/opencode-access.d.ts +13 -0
  69. package/dist/adapters/opencode-access.js +76 -0
  70. package/dist/adapters/opencode-access.js.map +1 -0
  71. package/dist/adapters/opencode-config.d.ts +11 -0
  72. package/dist/adapters/opencode-config.js +238 -0
  73. package/dist/adapters/opencode-config.js.map +1 -0
  74. package/dist/adapters/opencode-http.d.ts +28 -0
  75. package/dist/adapters/opencode-http.js +297 -0
  76. package/dist/adapters/opencode-http.js.map +1 -0
  77. package/dist/adapters/opencode-tools.d.ts +19 -0
  78. package/dist/adapters/opencode-tools.js +127 -0
  79. package/dist/adapters/opencode-tools.js.map +1 -0
  80. package/dist/adapters/opencode.d.ts +2 -0
  81. package/dist/adapters/opencode.js +569 -0
  82. package/dist/adapters/opencode.js.map +1 -0
  83. package/dist/adapters/rpc.d.ts +3 -0
  84. package/dist/adapters/rpc.js +45 -4
  85. package/dist/adapters/rpc.js.map +1 -1
  86. package/dist/adapters/types.d.ts +5 -0
  87. package/dist/adapters/types.js.map +1 -1
  88. package/dist/approvals/types.d.ts +1 -1
  89. package/dist/approvals/types.js.map +1 -1
  90. package/dist/cli/args.d.ts +1 -1
  91. package/dist/cli/args.js +4 -1
  92. package/dist/cli/args.js.map +1 -1
  93. package/dist/cli/dashboard-client.js +1 -1
  94. package/dist/cli/dashboard-client.js.map +1 -1
  95. package/dist/cli/dashboard-controller.d.ts +7 -0
  96. package/dist/cli/dashboard-controller.js +27 -0
  97. package/dist/cli/dashboard-controller.js.map +1 -0
  98. package/dist/cli/dashboard-detail-view.d.ts +1 -1
  99. package/dist/cli/dashboard-detail-view.js +3 -4
  100. package/dist/cli/dashboard-detail-view.js.map +1 -1
  101. package/dist/cli/dashboard-history-view.js.map +1 -1
  102. package/dist/cli/dashboard-input.d.ts +1 -1
  103. package/dist/cli/dashboard-input.js +11 -1
  104. package/dist/cli/dashboard-input.js.map +1 -1
  105. package/dist/cli/dashboard-layout.js +3 -3
  106. package/dist/cli/dashboard-layout.js.map +1 -1
  107. package/dist/cli/dashboard-renderer.js.map +1 -1
  108. package/dist/cli/dashboard-style.js +2 -2
  109. package/dist/cli/dashboard-style.js.map +1 -1
  110. package/dist/cli/dashboard.d.ts +2 -2
  111. package/dist/cli/dashboard.js +7 -32
  112. package/dist/cli/dashboard.js.map +1 -1
  113. package/dist/cli/help.d.ts +1 -1
  114. package/dist/cli/help.js +30 -12
  115. package/dist/cli/help.js.map +1 -1
  116. package/dist/cli/main.js +5 -1
  117. package/dist/cli/main.js.map +1 -1
  118. package/dist/config/access-provenance.d.ts +10 -0
  119. package/dist/config/access-provenance.js +31 -0
  120. package/dist/config/access-provenance.js.map +1 -0
  121. package/dist/config/access.d.ts +12 -2
  122. package/dist/config/access.js +125 -27
  123. package/dist/config/access.js.map +1 -1
  124. package/dist/config/loader.js +1 -0
  125. package/dist/config/loader.js.map +1 -1
  126. package/dist/config/oidc.js +4 -2
  127. package/dist/config/oidc.js.map +1 -1
  128. package/dist/config/project.js +2 -1
  129. package/dist/config/project.js.map +1 -1
  130. package/dist/config/resolve-access.js +24 -10
  131. package/dist/config/resolve-access.js.map +1 -1
  132. package/dist/index.d.ts +2 -2
  133. package/dist/index.js +1 -1
  134. package/dist/index.js.map +1 -1
  135. package/dist/process-diagnostics.d.ts +2 -0
  136. package/dist/process-diagnostics.js +11 -0
  137. package/dist/process-diagnostics.js.map +1 -0
  138. package/dist/runtime/access-errors.d.ts +4 -0
  139. package/dist/runtime/access-errors.js +25 -0
  140. package/dist/runtime/access-errors.js.map +1 -0
  141. package/dist/runtime/approval-registry.js +1 -1
  142. package/dist/runtime/approval-registry.js.map +1 -1
  143. package/dist/runtime/client.js +54 -14
  144. package/dist/runtime/client.js.map +1 -1
  145. package/dist/runtime/dashboard-sanitize.d.ts +2 -0
  146. package/dist/runtime/dashboard-sanitize.js +7 -0
  147. package/dist/runtime/dashboard-sanitize.js.map +1 -0
  148. package/dist/runtime/dashboard.d.ts +1 -1
  149. package/dist/runtime/dashboard.js +2 -3
  150. package/dist/runtime/dashboard.js.map +1 -1
  151. package/dist/runtime/definition.js +11 -1
  152. package/dist/runtime/definition.js.map +1 -1
  153. package/dist/runtime/select-native.js +26 -8
  154. package/dist/runtime/select-native.js.map +1 -1
  155. package/dist/runtime/worker-client.js +38 -13
  156. package/dist/runtime/worker-client.js.map +1 -1
  157. package/dist/sdk/definitions.d.ts +4 -1
  158. package/dist/sdk/definitions.js +16 -2
  159. package/dist/sdk/definitions.js.map +1 -1
  160. package/dist/sdk/permission-validation.js +10 -1
  161. package/dist/sdk/permission-validation.js.map +1 -1
  162. package/dist/sdk/types.d.ts +29 -1
  163. package/dist/sdk/types.js.map +1 -1
  164. package/package.json +4 -1
  165. package/sdk/access-config.md +58 -4
  166. package/sdk/adapter-contract.md +5 -3
  167. package/sdk/additional-harnesses.md +43 -0
  168. package/sdk/agent-skill.md +2 -2
  169. package/sdk/agent.md +5 -3
  170. package/sdk/approvals.md +3 -1
  171. package/sdk/authentication.md +1 -1
  172. package/sdk/cli/dashboard-design.md +6 -0
  173. package/sdk/cli/index.md +9 -6
  174. package/sdk/cli/output.md +3 -1
  175. package/sdk/config.md +1 -1
  176. package/sdk/copilot.md +53 -0
  177. package/sdk/cursor.md +68 -0
  178. package/sdk/diagnostics.md +29 -0
  179. package/sdk/distribution.md +1 -1
  180. package/sdk/evals.md +1 -1
  181. package/sdk/fx.md +50 -5
  182. package/sdk/harnesses.md +13 -13
  183. package/sdk/index.md +3 -2
  184. package/sdk/opencode.md +57 -0
  185. package/sdk/permissions.md +4 -2
  186. package/sdk/project-team.md +2 -0
  187. package/sdk/tools.md +1 -1
  188. package/sdk/v1-runtime.md +3 -3
package/sdk/cli/index.md CHANGED
@@ -46,7 +46,7 @@ subharness / trenton
46
46
  ◌ claude Review the current diff waiting 00:38
47
47
  ```
48
48
 
49
- The harness label is `codex`, `claude`, or `fx`. A direct target is known during startup; a specialist displays `pending` until its actual native harness is selected. Selection reports the successfully opened harness, including fallback selection. The title is the first nonempty line of the current task's original prompt, with whitespace normalized and terminal control sequences removed, bounded to 120 Unicode code points before fitting it to the display. An empty sanitized title is `(untitled)`. No model call generates titles. Steering retains the task title; a follow-up uses its own prompt.
49
+ The harness label is `codex`, `claude`, `fx`, `opencode`, `copilot`, or `cursor`. A direct target is known during startup; a specialist displays `pending` until its actual native harness is selected. Selection reports the successfully opened harness, including fallback selection. The title is the first nonempty line of the current task's original prompt, with whitespace normalized and terminal control sequences removed, bounded to 120 Unicode code points before fitting it to the display. An empty sanitized title is `(untitled)`. No model call generates titles. Steering retains the task title; a follow-up uses its own prompt.
50
50
 
51
51
  Time is elapsed wall time since that task first dispatched, including waiting and recovery. A queued task shows `00:00`. Completed, cancelled, and interrupted tasks freeze their elapsed time when that outcome is reached. Failed tasks freeze their elapsed time at failure and resume counting from the original start if explicitly recovered. Tasks cancelled before first dispatch show `00:00`. Repeated observation or cancellation that leaves a settled terminal outcome unchanged does not change its recorded finish time. If stopping previously unconfirmed execution reaches a new outcome, timing records that new outcome. Durations use `MM:SS` below one hour and `H:MM:SS` thereafter. State and elapsed time occupy separate aligned columns. Finished rows include completion age when space permits, as defined in [Dashboard presentation](dashboard-design.md). Narrow terminals truncate titles by display width without splitting grapheme clusters; when the fixed fields alone do not fit, the row is clipped to the available columns.
52
52
 
@@ -58,25 +58,28 @@ The command requires terminal stdout and a terminal supporting cursor control; n
58
58
 
59
59
  ## Direct harnesses and specialists
60
60
 
61
- `codex`, `claude`, and `fx` are reserved, case-sensitive target names for direct harness execution. `claude` selects the Claude Code adapter, whose SDK and access configuration key remains `claudeCode`. Direct execution needs an installed native harness and eligible access, but no TypeScript definition, project-local SDK import, or agent catalog evaluation. An invalid specialist file does not block a direct harness run.
61
+ `codex`, `claude`, `fx`, `opencode`, `copilot`, and `cursor` are reserved, case-sensitive target names for direct harness execution. `claude` selects the Claude Code adapter, whose SDK and access configuration key remains `claudeCode`. Direct execution needs its native runtime and eligible access, but no TypeScript definition, project-local SDK import, or agent catalog evaluation. An invalid specialist file does not block a direct harness run.
62
62
 
63
63
  ```sh
64
64
  subharness run claude "Review the current diff."
65
65
  subharness run codex --cwd ../feature-worktree "Implement the documented validation."
66
66
  subharness run fx --model "provider/model" "Compare the proposed implementations."
67
+ subharness run opencode --model "creator/model" "Inspect the current implementation."
68
+ subharness run copilot --model "creator/model" "Review the current diff."
69
+ subharness run cursor --model "CURSOR_MODEL_ID" "Implement the documented change."
67
70
  subharness run repo:reviewer "Review the current diff."
68
71
  subharness check repo:reviewer --format jsonl
69
72
  ```
70
73
 
71
- Replace `provider/model` with an available Gateway model identifier. Nonreserved bare names retain the existing unambiguous specialist lookup. Qualified `repo:`, `global:`, and `subagent:` names retain their existing meanings. A specialist named `claude`, `codex`, or `fx` requires its scope qualifier; it never shadows the built-in target. Unknown targets fail rather than being executed as arbitrary commands. Omitting the target is an argument error; the CLI never chooses the first installed harness.
74
+ Replace `provider/model` or `creator/model` with an available Gateway model identifier. Nonreserved bare names retain the existing unambiguous specialist lookup. Qualified `repo:`, `global:`, and `subagent:` names retain their existing meanings. A specialist named for any reserved harness target requires its scope qualifier; it never shadows the built-in target. Unknown targets fail rather than being executed as arbitrary commands. Omitting the target is an argument error; the CLI never chooses the first installed harness.
72
75
 
73
76
  Direct harness sessions use native instructions and project context without adding a specialist role, custom tools, or declared children. They preserve the existing authentication, native permission, queue, cancellation, follow-up, and response contracts. They do not broaden the caller's native permissions or automatically authorize additional delegation.
74
77
 
75
- `--model` and `--effort` configure direct harness targets only for `run` and `check`, and can be combined with `--cwd` and, for `run`, any supported prompt source. Empty values are errors. Specialist targets reject these overrides and retain their declared harness configurations. `send` retains the session configuration and does not accept model or effort overrides.
78
+ `--model` configures direct harness targets only for `run` and `check`, and can be combined with `--cwd` and, for `run`, any supported prompt source. `--effort` is additionally available for Codex, Claude Code, and fx. Empty values are errors. Specialist targets reject these overrides and retain their declared harness configurations. `send` retains the session configuration and does not accept model or effort overrides.
76
79
 
77
- Omitting `--model` requests the native default for the authorized access route at session creation. The adapter retains the selected model for that conversation. It does not inherit the calling agent's model, rank models, choose a substitute, or change billing routes. An unavailable or unverifiable native default fails with actionable guidance to supply `--model`; it does not submit a prompt merely to discover a default. Explicit model identifiers retain native validation and substitution checks. TypeScript harness constructors continue to require a model.
80
+ For Codex, Claude Code, and fx, omitting `--model` requests the native default for the authorized access route at session creation. OpenCode, Copilot, and Cursor require an explicit `--model`; omission fails with `INVALID_CONFIG` and guidance before native startup. The adapter retains the selected model for that conversation. It does not inherit the calling agent's model, rank models, choose a substitute, or change billing routes. An unavailable or unverifiable native default fails with actionable guidance to supply `--model`; it does not submit a prompt merely to discover a default. Explicit model identifiers retain native validation and substitution checks. TypeScript harness constructors continue to require a model.
78
81
 
79
- Effort is harness-specific: Codex and fx accept native effort identifiers, while Claude Code accepts `low`, `medium`, `high`, `xhigh`, or `max`. Explicit effort must be compatible with the selected model where native capabilities expose that validation. An omitted effort retains the native default at session creation. Detected changes to an explicit request are errors. Codex and Claude Code retain standard-speed execution; this interface adds no fast-mode flag. fx retains its documented native preference and Gateway access contract.
82
+ Effort is harness-specific: Codex and fx accept native effort identifiers, while Claude Code accepts `low`, `medium`, `high`, `xhigh`, or `max`. OpenCode, Copilot, and Cursor reject `--effort`. Explicit effort must be compatible with the selected model where native capabilities expose that validation. An omitted effort retains the native default at session creation. Detected changes to an explicit request are errors. Codex and Claude Code retain standard-speed execution; this interface adds no fast-mode flag. fx retains its documented native preference and Gateway access contract.
80
83
 
81
84
  Direct-harness help for `run` and `check` describes the relevant options and access requirements without loading definitions, starting a coordinator, or invoking a harness. Native CLI flags are not forwarded. Unsupported flags are errors.
82
85
 
package/sdk/cli/output.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # CLI Output
2
2
 
3
+ [Error diagnostics](../diagnostics.md) defines safe process and coordinator communication details. These details enrich message text without changing the error record shape or command exit-code rules.
4
+
3
5
  `dashboard` is a terminal-only live view, not an execution-record command. It accepts no `--format` option and emits no text/JSONL records on success. Its rows, empty state, and terminal lifecycle are defined in the [CLI contract](index.md#live-dashboard).
4
6
 
5
7
  Execution commands accept `--format text|jsonl`; `text` is the default. Both formats report the same operations. JSONL contains complete records separated by newlines, never native token streams or tool transcripts. All records include `version: 1` and a `type` discriminator. Identifiers are opaque strings prefixed with `ses_`, `tsk_`, `rsp_`, or `req_` and are not paths or process identifiers.
@@ -33,7 +35,7 @@ The identifiers above are illustrative. A `response` contains `sessionId`, `task
33
35
 
34
36
  `status` emits a `status` record with `sessionId`, `taskId`, `state`, and optional `response` and `error`. The response preview contains `responseId`, `text`, and `truncated`; at most 4,000 text characters are included. `subharness status <task-id> --full` returns the complete latest response instead. `subharness wait <task-id>` returns or awaits the first retained response; adding `--after <response-id>` returns or awaits the next response after that cursor.
35
37
 
36
- `list` emits an `agents` record with an `agents` array of `{ id, name, description, scope }`, where scope is `harness`, `repo`, `global`, or `subagent`. The built-in entries have IDs and names `codex`, `claude`, and `fx`, and scope `harness`; they appear in that order before discovered specialists. They describe supported targets, not verified executable, authentication, or model availability. A managed parent's catalog includes its declared `subagent:` entries; generic parents have no declared children. `queue` emits a `queue` record with `sessionId`, `paused`, optional `active`, and a `tasks` array in pending order. Task summaries contain `taskId`, `state`, and a prompt `description` limited to 120 characters.
38
+ `list` emits an `agents` record with an `agents` array of `{ id, name, description, scope }`, where scope is `harness`, `repo`, `global`, or `subagent`. The built-in entries have IDs and names `codex`, `claude`, `fx`, `opencode`, `copilot`, and `cursor`, and scope `harness`; they appear in that order before discovered specialists. They describe supported targets, not verified executable, authentication, or model availability. A managed parent's catalog includes its declared `subagent:` entries; generic parents have no declared children. `queue` emits a `queue` record with `sessionId`, `paused`, optional `active`, and a `tasks` array in pending order. Task summaries contain `taskId`, `state`, and a prompt `description` limited to 120 characters.
37
39
 
38
40
  An `accepted` record contains `sessionId`, `taskId`, `delivery: "steer"`. A successful `cancel` emits a `cancelled` record with the targeted task identity and final state, after affected native execution has stopped. Already-terminal tasks retain their existing state. `resume` emits `started` for the existing task with `resumed: true`, then its next response or terminal outcome.
39
41
 
package/sdk/config.md CHANGED
@@ -39,7 +39,7 @@ The former `.agents/agents/` directory is not read. Definitions moved to `.subha
39
39
 
40
40
  Discovery is required for listing and repository/global specialist lookup. Direct harness execution skips it. Declared-child execution loads only the parent's source and direct child map; unrelated catalog entries are not dependencies of a `subagent:` invocation.
41
41
 
42
- The declared name determines identity. Duplicate names in the same scope are errors. `repo:reviewer` and `global:reviewer` remain distinct; bare `reviewer` is accepted only when unambiguous. The reserved CLI targets `codex`, `claude`, and `fx` always select native harnesses. Specialists with those names require a `repo:` or `global:` qualifier. Direct harness runs bypass definition discovery entirely, including invalid definition files. Global definitions can execute in any caller-supplied directory. Global and repository files resolve their own imports through normal Node package resolution.
42
+ The declared name determines identity. Duplicate names in the same scope are errors. `repo:reviewer` and `global:reviewer` remain distinct; bare `reviewer` is accepted only when unambiguous. The reserved CLI targets `codex`, `claude`, `fx`, `opencode`, `copilot`, and `cursor` always select native harnesses. Specialists with those names require a `repo:` or `global:` qualifier. Direct harness runs bypass definition discovery entirely, including invalid definition files. Global definitions can execute in any caller-supplied directory. Global and repository files resolve their own imports through normal Node package resolution.
43
43
 
44
44
  ```sh
45
45
  subharness list --cwd /repo/worktree
package/sdk/copilot.md ADDED
@@ -0,0 +1,53 @@
1
+ # GitHub Copilot adapter
2
+
3
+ The Copilot adapter uses the native GitHub Copilot SDK over a dedicated stdio runtime process. The pinned SDK is `@github/copilot-sdk` 1.0.14, with native protocol version 3 as exposed by Copilot runtime 1.0.85. It does not implement a model loop. The public model-only configuration and access routes are defined in [additional harnesses](additional-harnesses.md).
4
+
5
+ ## Native GitHub access
6
+
7
+ An explicit `subscription` connection uses the native Copilot or GitHub CLI login. An `api-key` connection with `provider: "github"` instead reads the selected GitHub token, defaulting to `COPILOT_GITHUB_TOKEN`. The token must be eligible for Copilot; its presence alone does not prove entitlement. Neither route uses BYOK or Vercel Gateway.
8
+
9
+ The adapter removes competing ambient tokens and provider overrides. Saved-login access enables native logged-in-user discovery without passing a token; explicit GitHub access supplies the selected `gitHubToken` to the SDK client and session and disables logged-in-user fallback. Startup checks native authentication status and exact native model-catalog membership without generation. Saved-user or GitHub CLI authentication must not be confused with an environment token. Unknown authentication metadata and route changes fail explicitly. Auto-routing models are not accepted. Native login and refresh remain the harness's responsibility. Saved-login access preserves the native Copilot home so last-user metadata, keychain credentials, file-backed credentials, and GitHub CLI discovery remain native. Each session still uses a private `configDirectory` with configuration discovery disabled. Explicit GitHub-token, BYOK, and Gateway routes use a private runtime base directory as well. Subharness never reads or copies native credentials or imports personal provider/model configuration. Cleanup removes only adapter-owned private state. This preserves the existing manual approval and managed-policy behavior; it does not import personal permission configuration.
10
+
11
+ ## Direct provider API keys
12
+
13
+ Copilot BYOK connections use `type: "api-key"` with `provider: "openai"`, `"anthropic"`, or `"azure"`. The selected variable defaults to `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `AZURE_OPENAI_API_KEY`, respectively; `env` and `envFile` can select another source. These routes disable GitHub login and configure one singular native provider, so requests use the chosen provider's billing.
14
+
15
+ ```json
16
+ {
17
+ "access": {
18
+ "copilot": [{ "type": "api-key", "provider": "openai", "wireApi": "responses" }]
19
+ }
20
+ }
21
+ ```
22
+
23
+ OpenAI defaults to `https://api.openai.com/v1`, and Anthropic defaults to `https://api.anthropic.com`. `baseUrl` can select another compatible endpoint; Azure requires it and expects its native resource/project URL. OpenAI-compatible services use `provider: "openai"` and their full API prefix. OpenAI/Azure accept `wireApi: "completions" | "responses"`, defaulting to `completions`; Anthropic uses Messages and rejects `wireApi`. Azure alone accepts `apiVersion`, passed to the SDK's native Azure option. HTTP transport is used.
24
+
25
+ The agent's `model` is the native behavior model. Optional `wireModel` supplies a different remote model or Azure deployment name; omission uses the agent model on the wire too. The adapter passes these explicit values without inventing aliases. Readiness verifies the native model and configured provider/endpoint/credential representation. A BYOK assistant response can label its model with the remote name or deployment; native model RPC readback remains the authority for the pinned behavior model. BYOK has no universal remote catalog check: readiness does not prove a remote model exists or that a key has quota. Neither configured readback nor a user-supplied endpoint proves the remotely executed model.
26
+
27
+ Custom headers, bearer-token callbacks, experimental mixed-provider sessions, and provider options outside the documented access shape are not exposed. Gateway connections remain a separate supported route with their existing fixed endpoint and `creator/model` names.
28
+
29
+ ## Gateway access
30
+
31
+ The adapter accepts explicit Gateway API-key or project OIDC connections. It configures a single native OpenAI-compatible provider with the fixed base URL `https://ai-gateway.vercel.sh/coding-agent/v1`, HTTP Chat Completions, and the exact requested `creator/model` identifier. API-key access supplies the selected API key; OIDC uses bearer-token authentication. GitHub login and unrelated provider credentials are disabled for this inference route. Ambient `COPILOT_PROVIDER_*` settings, model preferences, alternate endpoints, and native logged-in-user discovery must not override it.
32
+
33
+ A dedicated private native configuration/state directory prevents stored provider settings or plugins from changing billing. Native repository instructions and the caller's working directory remain available. Credentials are passed through the private SDK/protocol configuration, never process arguments or user-visible diagnostics. Startup uses the native protocol handshake, session creation, current-model and provider-endpoint introspection to verify the selection without submitting a prompt. The native allowed model list is restricted to the selected identifier. Unverifiable or changed selection is an explicit configuration error, not an access fallback.
34
+
35
+ The SDK's bundled runtime may be used; a separate global Copilot installation is not required when that runtime is available. Missing or incompatible runtime support is `HARNESS_UNAVAILABLE`. `check copilot --model creator/model` checks startup and cleanup only, not remote allowance.
36
+
37
+ ## Tools and approvals
38
+
39
+ Declared tools use native SDK tool callbacks and preserve validated text/image results. Copilot's result envelope groups text and images separately: text blocks are joined in order, and images retain their relative order as binary image results. Interleaving between those groups is not representable. Specialist instructions supplement the native system instructions; they never replace the harness's tool loop. Tool names retain their definition keys; a collision with a native built-in tool is an explicit configuration error, never an override. Callbacks are admitted only while a task is active, and interruption/close drain already-admitted callbacks.
40
+
41
+ The adapter uses the native manual permission mode and forwards supported active permission requests through the shared approval flow. Only the specific offered once/deny decisions are exposed initially; it does not invent persistent permission grants. The action context is bounded and excludes credential-bearing configuration. Unsupported input or startup requests fail with `INPUT_REQUIRED` and stop affected work. No callback automatically approves native commands or expands native permissions for declared children.
42
+
43
+ Enterprise managed-policy self-fetch is enabled for explicit GitHub-token access, which supplies the session identity required by the SDK. Saved-login, BYOK, and Gateway routes omit that opt-in because they do not supply a session GitHub token; the adapter does not extract one or promise enterprise policy self-fetch for those routes. Native manual approval requirements remain enabled on every route. A permission request that specifically requires human-only provenance or an unrepresentable sandbox bypass is unsupported and fails with `INPUT_REQUIRED`; a Subharness caller response must not be relabeled as a verified human decision. Requests already resolved by native hooks are not presented as new approval requests. Native withdrawal retires the matching request and late answers are ignored.
44
+
45
+ ## Lifecycle
46
+
47
+ Follow-ups reuse the native session. Events are correlated to the active turn; a final assistant message alone is not successful completion. A session-idle event is accepted in any native session mode after evidence that the submitted turn started, and only when no native work remains. A stale idle event cannot complete a newly submitted task. The adapter reports native shutdown or transport loss as an execution failure and limits final response text to 1 MiB. Model or endpoint substitutions fail without replay. Turn completion withdraws remaining approval requests.
48
+
49
+ Interruption stops tool admission, withdraws pending approvals, requests native abort, confirms no native work remains, and waits for admitted callbacks. An abort acknowledgement alone does not prove the native process stopped. Native cancellation requests and status checks are bounded; a cancellation that cannot establish idle/termination returns `CANCELLATION_FAILED`. Already-admitted host callbacks are drained without imposing that native cancellation deadline on their execution. Steering uses the coordinator's interrupt behavior, and prompt-free recovery returns `RECOVERY_UNSUPPORTED`.
50
+
51
+ An unconfirmed interruption fails the active turn and prevents further tasks in that session. Tool admission remains closed, and close must still attempt native cleanup. The turn cannot later report success after continuing with disabled tool callbacks. This rule also applies while native prompt admission is pending.
52
+
53
+ Close retires the session, shuts down the dedicated native runtime, confirms termination, drains tools, and removes private state. Cleanup RPCs are bounded so an unresponsive session cannot prevent process shutdown attempts. Escalated termination without confirmed exit produces `CANCELLATION_FAILED`, never successful cleanup. Startup failure also cleans up. A successful readiness record requires completed runtime cleanup. Raw SDK errors and process output are replaced with fixed diagnostics so credentials do not enter CLI records.
package/sdk/cursor.md ADDED
@@ -0,0 +1,68 @@
1
+ # Cursor adapter
2
+
3
+ The Cursor adapter runs the native Cursor CLI for subscription access and the native Cursor TypeScript SDK for explicit API-key access against the caller's local working directory. Cursor owns inference, tools, conversation state, and context management. Cloud agents are not part of this adapter.
4
+
5
+ ## Configuration
6
+
7
+ ```ts
8
+ import { cursor } from "subharness";
9
+
10
+ cursor({ model: "CURSOR_MODEL_ID", sandboxMode: "enabled" });
11
+
12
+ interface CursorOptions {
13
+ readonly model: string;
14
+ readonly sandboxMode?: "enabled" | "disabled";
15
+ }
16
+
17
+ interface CursorConfig extends CursorOptions {
18
+ readonly kind: "cursor";
19
+ }
20
+ ```
21
+
22
+ The constructor returns an immutable configuration. Model is required and must be nonempty. Unknown options, including `fast` and `effort`, are rejected. For API-key access, `sandboxMode` maps to the native SDK's local sandbox option. Omission preserves the SDK default, which runs local tools without interactive approval and without a sandbox. The native sandbox, when enabled, restricts shell writes and network access according to Cursor's native policy; it is not a sandbox for host-side custom tool callbacks. The adapter never enables broader permissions to make declared-child launches succeed.
23
+
24
+ The CLI target is `cursor`. `run cursor` and `check cursor` require `--model`. The following catalog behavior applies to API-key access; subscription model selection is defined below. The native routing IDs `auto` and `auto-smart`, including catalog aliases that resolve to either ID, are rejected because they do not retain a concrete model. The catalog has no generic router flag; the adapter does not infer routing from display names or invent additional reserved IDs. `--effort` is unsupported for this adapter. Native model aliases are accepted only when the account catalog supplies their mapping. Startup verifies the account and selected model through the native SDK without a generation, creates an empty local agent, and pins the resolved selection for follow-ups. When terminal results report a model, a detected replacement fails explicitly without replay. The agent handle's configured model is not evidence of the model that executed a run.
25
+
26
+ ## Access
27
+
28
+ Personal access uses the `cursor` key and requires an explicit connection. A `subscription` connection uses the current native Cursor CLI login; the user completes `cursor-agent login` outside Subharness. An `api-key` connection uses the SDK and defaults to `CURSOR_API_KEY`. Both environment and explicit dotenv references follow the shared [access contract](access-config.md). Omission does not discover or enable a connection, and an empty list disables Cursor. Native login and API-key access are separate billing routes; neither is an implicit fallback for the other. Vercel API-key and OIDC connections are unsupported and fail with `UNSUPPORTED_OPTION` before startup. A Cursor API key is a Cursor billing route, not a Gateway credential.
29
+
30
+ ```json
31
+ {
32
+ "access": {
33
+ "cursor": [{ "type": "subscription" }]
34
+ }
35
+ }
36
+ ```
37
+
38
+ For API-key access, the selected key is passed explicitly to the SDK. Subscription access delegates credential discovery to the native CLI; Subharness never reads, copies, or transfers its saved tokens. A missing or expired native login fails with `ACCESS_UNAVAILABLE` and login guidance before submission. Subharness does not open a browser or perform an interactive login. Explicit API-key/auth-token environment variables must not silently override a subscription connection. Backend or website endpoint overrides through `CURSOR_BACKEND_URL` or `CURSOR_WEBSITE_URL` are rejected before the key is used. This also applies to the SDK host environment, because the SDK reads process-level settings. The adapter does not transfer subscription tokens, change account-synced provider settings, or treat the editor's custom-provider configuration as verified Gateway routing. Credentials and raw native errors must not appear in diagnostics.
39
+
40
+ ## API-key session behavior
41
+
42
+ Successive tasks use the same native agent. Specialist instructions supplement the native harness instructions in the first user turn; they do not replace Cursor's system prompt. Declared tools use native SDK custom tools, validate inputs, preserve text and image results, and stop admitting calls when the task stops. Cancellation and close wait for admitted callbacks to settle.
43
+
44
+ Active steering returns `UNSUPPORTED_DELIVERY`; the coordinator applies its documented interrupt-and-replace behavior. Interruption cancels the active native run and waits for terminal completion. Failure to confirm native stop returns `CANCELLATION_FAILED`, fails the active turn, and prevents further tasks in that session. Tool admission remains closed; close must still dispose the native agent and drain admitted callbacks. Prompt-free recovery returns `RECOVERY_UNSUPPORTED`. A turn succeeds only with a successful terminal result and returns its final text. Responses are limited to 1 MiB.
45
+
46
+ The SDK's headless permission decisions remain native. This SDK version exposes no supported interactive approval or input channel to the adapter. Its `request` message records a backend request identifier and is not an approval request. Native run failures produce a sanitized execution error; the adapter does not invent an `INPUT_REQUIRED` mapping from undocumented error codes. Close disposes the native agent and drains custom tools. `check cursor` verifies credential/model discovery, local agent creation, and disposal without submitting a prompt; it does not prove quota or that a later shell command will be permitted.
47
+
48
+ ## Subscription protocol and lifetime
49
+
50
+ Subscription access uses the installed `cursor-agent` executable with its native ACP protocol over standard input and output. The supported CLI release is `2026.09.23-86fc751`, using ACP version 1. Other releases fail before input with `HARNESS_UNAVAILABLE` and compatibility guidance. The executable name is explicit because `agent` is also a Subharness compatibility alias. A session owns one native process and one native conversation in the requested working directory. Subscription access currently supports macOS and Linux, where the adapter can own and terminate a native process group. Windows subscription startup fails with `UNSUPPORTED_OPTION`; the SDK API-key route is unchanged.
51
+
52
+ The transport accepts newline-delimited JSON-RPC 2.0, correlates responses by request ID, and rejects malformed envelopes or oversized protocol frames with `PROTOCOL_ERROR`. Individual frames are limited to 16 MiB; returned assistant text remains limited to 1 MiB. Native standard error and raw error messages are not forwarded to callers. Startup and configuration requests are bounded; model execution itself has no arbitrary completion deadline. Transport loss fails pending operations and retires the native process rather than leaving a task pending indefinitely.
53
+
54
+ Native cancellation sends `session/cancel` and requires the active `session/prompt` to finish before confirming interruption. A cancellation timeout retires and poisons the session with `CANCELLATION_FAILED`; it does not replay input or silently open a replacement conversation. Closing stops admitting tool calls, retires the native process, and drains admitted custom-tool callbacks. Process retirement uses bounded termination and confirms process exit; failure to establish termination is an error. Tool callbacks have their own drain lifetime and are not falsely marked cancelled by a native timeout. Queued follow-ups reuse the same conversation after ordinary completion or confirmed native cancellation. Active steering and prompt-free recovery remain unsupported.
55
+
56
+ ## Subscription startup and capabilities
57
+
58
+ Subscription access preserves native credential ownership. It removes `CURSOR_API_KEY` and `CURSOR_AUTH_TOKEN` from the child environment and does not call ACP `authenticate`, `login`, or `logout`. Native credential discovery, refresh, and account eligibility remain Cursor's responsibility. The adapter checks bounded `status --format json` output for authenticated access/refresh availability, then requires authenticated ACP session creation and model discovery. Status alone is not proof of readiness, quota, subscription-plan eligibility, or credential history. The `subscription` connection selects Cursor's saved native CLI account route; it does not attest how those native credentials were originally created or impose an account spending cap.
59
+
60
+ A private owner-only configuration and data directory isolates model selection and session state. Native non-credential permission and network settings are preserved in the private configuration; project permission rules continue to apply. Shared user/project configuration is never rewritten. Alternate Cursor endpoints, authless/local-provider settings, and Bedrock activation are unsupported and rejected before native startup. Ordinary AWS credentials are not rejected merely because unrelated tools may use them. Native API keys, custom endpoints, or API-key helpers cannot silently select a different inference route. Subharness-created configuration files use mode `0600`; native-generated files remain inside the owner-only directory. Private state is removed after confirmed process shutdown. The native credential store is neither copied nor exposed through diagnostics.
61
+
62
+ Startup negotiates ACP version 1 with the native parameterized model picker. The required model must match a concrete base ID in the returned native catalog; CLI display aliases and bracketed variant strings are not inferred. Native model parameters retain their defaults for that model. Auto routing IDs `auto`, `auto-smart`, `default`, and `default[]` are rejected. The selected model is applied with `session/set_config_option` and verified from its returned configuration before each prompt. A reported change fails explicitly. The adapter does not claim configured model readback proves the remotely executed model; this native protocol does not expose executed-model metadata in its terminal result. For example, `cursor({ model: "gpt-5-mini" })` selects that base model when present in the account catalog. A CLI display variant such as a model name with an effort suffix is not automatically treated as the same base ID.
63
+
64
+ For subscription access, either explicit `sandboxMode` value fails with `UNSUPPORTED_OPTION` before submission because ACP does not expose a verified sandbox control. Omitting it uses Cursor's native ACP execution and permission behavior; it does not enable a Subharness sandbox. The API-key route retains its SDK sandbox option.
65
+
66
+ Declared tools use a uniquely named private MCP server supplied in `session/new`. The adapter verifies that the native client initializes the server before admitting prompts; a skipped or failed native MCP connection is a startup error. MCP request bodies are limited to 16 MiB and headers to 16 KiB. Text and image results retain their MCP content types and shared tool-result limits. Native approval rules still apply. Active `session/request_permission` requests expose only the offered allow-once and reject-once choices through the shared approval flow with `harness: "cursor"`; persistent allow-always/reject-always choices are not exposed. Original native option IDs are retained. Unsupported or malformed interactive requests, including questions and plan approval, fail with `INPUT_REQUIRED` and cancel the native turn. Startup-time interactive requests are unsupported. Withdrawal, terminal completion, cancellation, and close retire pending requests; late answers never grant permission.
67
+
68
+ A terminal ACP `end_turn` returns the accumulated assistant text. `cancelled` is interruption; refusal or exhausted-limit terminal reasons and RPC/transport failures reject with a sanitized execution error. This CLI release can render some backend failures as ordinary assistant text followed by `end_turn`, without a separate failure signal. Such text is returned as native output; a completed Subharness task on this route means the native turn ended, not that every backend operation succeeded. The adapter does not guess error status from prose. Raw transport diagnostics remain private. This capability limit is specific to the subscription ACP route; the API-key SDK route retains its typed native results.
@@ -0,0 +1,29 @@
1
+ # Error Diagnostics
2
+
3
+ Error records retain their existing `{ code, message }` shape. Messages describe the operation that failed and include safe, observed context that helps callers identify the cause. The diagnostics described here never include raw native stderr, SDK exception text, HTTP response bodies, RPC error messages or data, prompts, credential values, or configuration contents. Unknown native values receive a fixed generic explanation rather than being echoed. Paths included in these diagnostic cases are quoted with C0, C1, DEL, and Unicode line separators escaped.
4
+
5
+ ## Claude startup and turn failures
6
+
7
+ Claude startup distinguishes native account inspection, model catalog retrieval, and model settings validation. An unexpected exception from account inspection or model catalog retrieval is `HARNESS_FAILED`, with the failed phase identified. Unexpected exceptions after successful access verification are also harness failures identified by the current startup phase. They do not establish unavailable access and do not permit connection or harness fallback. A completed account inspection that demonstrates unavailable or incompatible access retains `ACCESS_UNAVAILABLE` and its existing eligible fallback behavior. Existing explicit configuration, settings capability, model, and effort errors retain their codes and guidance, including `--model` guidance for an unverifiable native default. Cleanup and no-prompt-before-verification rules remain unchanged.
8
+
9
+ Claude terminal result failures retain `HARNESS_ERROR`. Recognized result subtypes distinguish a native turn limit, a native budget limit, exhausted structured-output retries, and an error during execution. Messages describe the reported category without claiming an unobserved provider cause, quoting native error text, or promising that Subharness exposes configuration for every native limit. Unknown subtypes and unsuccessful results without a recognized category receive a fixed generic turn-failure message. A reported execution failure is never automatically retried or replayed.
10
+
11
+ ## Native protocol and process failures
12
+
13
+ Codex and fx RPC rejection messages identify the requested native method and include the native error code only when it is a safe integer. Known JSON-RPC codes use fixed categories: `-32700` is a parse error, `-32600` an invalid request, `-32601` an unavailable method, `-32602` invalid parameters, and `-32603` an internal error. Other safe integer codes remain numeric without an invented interpretation. Missing or malformed codes are not printed. A generic rejection does not claim that authentication or native configuration caused the error. Existing steering and session-option capability classifications retain their Subharness error codes and useful recovery guidance. Freeform native messages and error data are never forwarded.
14
+
15
+ When an observed process termination causes an error, diagnostics identify the process and include its observed exit code or recognized termination signal when available. This applies to Codex and fx transports, the Claude subprocess owned by the adapter, session workers, and coordinator startup. A signal does not establish why it was sent; for example, `SIGKILL` does not by itself prove an out-of-memory condition. Missing termination metadata is omitted. Cleanup-induced termination must not replace or be described as the cause of an earlier failure. Adding diagnostics does not wait indefinitely for process exit or weaken bounded shutdown.
16
+
17
+ Worker failures identify the pending operation when available, such as startup, turn submission, steering, interruption, recovery, or closing. Coordinator failures distinguish failure to spawn, early exit, and startup timeout, retaining existing retirement and endpoint-publication safeguards. Only fixed operation labels and recognized system error categories may be added; raw operating-system exception text is not forwarded.
18
+
19
+ ## Coordinator communication
20
+
21
+ Coordinator communication failures retain `COORDINATOR_UNAVAILABLE`. A non-success HTTP response identifies its numeric status and a recognized requested operation, when available. A successful response with no body is distinguished from HTTP rejection. Invalid JSON records, an incomplete final record, and an interrupted response stream have distinct fixed explanations. Transport failures retain the statement that the task was not automatically retried. These diagnostics do not expose endpoint tokens, raw request or response contents, or arbitrary operation names. They do not infer whether a task completed from an HTTP or transport failure and do not automatically replay it.
22
+
23
+ ## Access configuration and OIDC
24
+
25
+ Personal-access schema errors retain `INVALID_CONFIG` and identify their structural location: the root object, `access`, a recognized harness entry such as `access.claudeCode`, or a zero-based connection location such as `access.claudeCode[0]`. A known invalid connection property may extend that location, for example `access.claudeCode[0].env`. Unknown property names or harness names are not echoed because arbitrary keys can contain sensitive values. An unknown connection property identifies its containing connection. Errors raised while loading a file also identify its absolute, safely quoted main-checkout path, or execution-project path outside Git. Invalid JSON and file-read errors identify the same safely quoted path. Validation happens before any connection is attempted; it does not fabricate attempted-access context.
26
+
27
+ An inaccessible execution directory is identified by its safely quoted caller-supplied path in both the CLI and project resolver. A missing credential file identifies its safely quoted configured `envFile` reference; it retains `ACCESS_UNAVAILABLE` and eligible fallback behavior. These messages preserve the existing path resolution rules and do not read credential contents to enrich an error.
28
+
29
+ OIDC expiration and not-yet-valid claims have separate diagnostics, both retaining `INVALID_CONFIG`. Expiration directs the caller to refresh the configured credential source. A future not-before claim explains that the token is not yet valid and suggests checking the system clock or waiting until validity begins; it does not assert that the clock is wrong. If both conditions apply, expiration is reported first. No token values or raw claims are printed. Claim-validation rules, project matching, and credential-source selection remain unchanged.
@@ -4,7 +4,7 @@ The npm package name is `subharness`. One package provides the TypeScript SDK an
4
4
 
5
5
  The source repository is [vercel-labs/subharness](https://github.com/vercel-labs/subharness). Its GitHub visibility is internal, so cloning requires repository access. The product name is subharness. The primary CLI command is `subharness`; `agent` remains an identical compatibility alias. Agent discovery and personal configuration live under `.subharness/`.
6
6
 
7
- Node.js 22.18 or newer is required. The SDK is ESM and includes TypeScript declarations. The native Codex, Claude Code, and fx executables remain external prerequisites; installing this package does not install harnesses or configure their credentials.
7
+ Node.js 22.18 or newer is required. The SDK is ESM and includes TypeScript declarations. Installing this package supplies the pinned Copilot and Cursor SDK dependencies. It does not configure native harness credentials or install the Codex, Claude Code, fx, OpenCode, or Cursor executables. Cursor subscription access requires the separately installed `cursor-agent` CLI; Cursor API-key access uses the bundled SDK dependency. The Copilot SDK may supply its compatible runtime as defined in the [Copilot contract](copilot.md).
8
8
 
9
9
  ## Installation and resolution
10
10
 
package/sdk/evals.md CHANGED
@@ -41,7 +41,7 @@ resolveEvalAccess(options: {
41
41
  }): Promise<EvalAccess | EvalAccessError>
42
42
  ```
43
43
 
44
- `HarnessKind` uses the existing `codex`, `claudeCode`, and `fx` identifiers. The harness list is nonempty and has no duplicates. IDs are nonempty strings. `minimumValidityMs` is a positive finite safe integer. The default environment is `process.env`, and the default clock is `Date.now` in milliseconds. Input errors are returned before native startup; this function never starts a harness or makes a network request.
44
+ The evaluation harness discriminator remains limited to the original `codex`, `claudeCode`, and `fx` identifiers. The harness list is nonempty and has no duplicates. IDs are nonempty strings. `minimumValidityMs` is a positive finite safe integer. The default environment is `process.env`, and the default clock is `Date.now` in milliseconds. Input errors are returned before native startup; this function never starts a harness or makes a network request.
45
45
 
46
46
  `EvalAccessError` is a typed returned error, not an exception-based domain result. Its `reason` is one of `invalid-input`, `policy`, `credentials-unavailable`, `validation`, `identity`, or `insufficient-lifetime`. Its message is exactly `Evaluation access is unavailable.` for every reason; it never retains raw caught exceptions, credentials, token claims, or native output. A policy error includes absent keys, a disabled participating harness, non-OIDC routes, or fallback lists. Credential reading failures are credentials-unavailable; malformed/expired/not-yet-valid credentials or linkage validation failures are validation. A valid linked token whose project or organization differs from the independent expectation is identity. Insufficient remaining validity uses insufficient-lifetime. Unclassified access-layer failures are validation, not guessed native authentication causes.
47
47
 
package/sdk/fx.md CHANGED
@@ -27,14 +27,13 @@ function fx(options: FxOptions): FxConfig;
27
27
 
28
28
  `FxConfig` is a readonly harness configuration with `kind: "fx"`, the required `model`, optional `effort`, and optional `permissionMode`. It is a member of `HarnessConfig` and can appear alone or in an ordered `harness` array. The constructor only validates and declares configuration; it does not start a process or access credentials. Unknown fields, including `fast`, are rejected. Native fx does not expose a compatible fast-mode selector in the supported ACP interface; its native fast-mode preference remains in effect.
29
29
 
30
- Models use the exact AI Gateway `provider/model` identifier. An explicit effort must be supported by the native session's advertised configuration for that model. Unsupported effort fails with `UNSUPPORTED_OPTION` before a task is submitted. Omitting effort preserves the native model's default. The adapter verifies the selected model and explicit effort; it does not silently substitute a model. A model appearing in the catalog does not guarantee access through a particular Gateway team or key.
30
+ Gateway models use the exact AI Gateway `provider/model` identifier. Other routes use their native model identifier without inferring the authentication provider from the model name. An explicit effort must be supported by the native session's advertised configuration for that model. Unsupported effort fails with `UNSUPPORTED_OPTION` before a task is submitted. Omitting effort preserves the native model's default. The adapter verifies the selected model and explicit effort; it does not silently substitute a model. A model appearing in the catalog does not guarantee access through a particular Gateway team or key.
31
31
 
32
- Direct CLI invocation does not require a definition: `subharness run fx "Review the current diff."` uses the native Gateway default model when it can be verified before submission. `--model <provider/model>` selects it explicitly. Both forms retain the access and permission requirements below; neither discovers a subscription or enables ambient paid credentials. The TypeScript constructor still requires `model`.
32
+ Direct CLI invocation does not require a definition: `subharness run fx "Review the current diff."` uses the selected native provider's default model when it can be verified before submission. `--model <provider/model>` selects it explicitly. Both forms retain the access and permission requirements below; neither discovers a subscription or enables ambient paid credentials. The TypeScript constructor still requires `model`.
33
33
 
34
34
  ## Access
35
35
 
36
- fx supports explicit `vercel-api-key` and `vercel-oidc` connections through the existing personal access file. It does not discover subscriptions, reuse another harness's subscription, or infer paid access from ambient credentials. Omitting `access.fx` leaves fx without an enabled connection. An empty array explicitly disables it. A `subscription` connection is unavailable; direct `api-key` access is unsupported by this adapter and fails with `UNSUPPORTED_OPTION`.
37
-
36
+ fx accepts explicitly selected Gateway API-key/OIDC access, native saved logins, and API keys for native custom connections. Omitting `access.fx` leaves fx without an enabled connection; an empty array explicitly disables it. Ambient credentials do not enable a route. Gateway connections retain their existing shape and behavior; the following example selects one explicitly.
38
37
  ```json
39
38
  {
40
39
  "access": {
@@ -45,7 +44,53 @@ fx supports explicit `vercel-api-key` and `vercel-oidc` connections through the
45
44
  }
46
45
  ```
47
46
 
48
- The connection reads only the named variable from the selected file. Existing main-checkout and worktree path rules apply. The adapter supplies the selected credential through the fx subprocess environment, fixes the native provider to AI Gateway, and removes competing credential variables and endpoint overrides. It does not save the key in native settings or place it in process arguments. Native shell processes can inherit that environment, so the credential is available within the native process tree. ACP does not provide an isolated credential channel for this release. Credential isolation from native tools belongs to the external harness or execution environment; this adapter does not provide it.
47
+ ## Native saved logins and custom API keys
48
+
49
+ Expanded access is verified against fx 0.0.11 and requires the described native status and ACP provider capabilities. Existing Gateway compatibility with fx 0.0.9 is retained.
50
+
51
+ A `subscription` connection requires `provider: "gateway"`, `"codex"`, or `"grok"`. The corresponding native setup is `fx login`, `fx login codex`, or `fx login grok`, performed outside Subharness. These are fx-owned logins; the adapter never imports another harness's tokens. `gateway` selects the saved Vercel login and still bills AI Gateway. The connection type identifies native saved-login access, not proof of a subscription plan or free usage.
52
+
53
+ ```json
54
+ { "access": { "fx": [{ "type": "subscription", "provider": "codex" }] } }
55
+ ```
56
+
57
+ For saved Gateway login, native settings must explicitly select `credential_source: "fx_login"`. An automatic preference or a stored-key preference is insufficient because refresh must not fall through to another billing source. The adapter does not change that preference. Native status must report the exact selected login source; startup then initializes native ACP with the same environment. Native discovery, refresh, credential migration, and persistence remain fx's responsibility and may update its own credential stores. Subharness does not read or copy those stores. Local status and successful initialization do not prove remote entitlement or quota.
58
+
59
+ For direct `api-key`, `provider` names a preexisting connection in `~/.fx/settings.json`, and `env` explicitly selects the input credential variable. The native connection must use `protocol: "openai-chat-completions"` and `auth: { "type": "bearer", "env": "NATIVE_KEY_SLOT" }`. Built-in provider names cannot be used for this route. The adapter reads bounded connection metadata, resolves the selected input key, and supplies it only to the native connection's declared environment slot in the child. Input and output variable names can differ. The adapter never writes the key or endpoint into native settings.
60
+
61
+ ```json
62
+ {
63
+ "access": {
64
+ "fx": [{ "type": "api-key", "provider": "openrouter", "env": "MY_ROUTER_KEY", "envFile": ".env.local" }]
65
+ }
66
+ }
67
+ ```
68
+
69
+ A corresponding native connection, configured through fx, can be:
70
+
71
+ ```json
72
+ {
73
+ "providers": {
74
+ "openrouter": {
75
+ "protocol": "openai-chat-completions",
76
+ "base_url": "https://openrouter.ai/api/v1",
77
+ "auth": { "type": "bearer", "env": "OPENROUTER_API_KEY" }
78
+ }
79
+ }
80
+ }
81
+ ```
82
+
83
+ Connection names follow native fx syntax: `[A-Za-z][A-Za-z0-9_-]*`, at most 64 characters, with built-in names reserved case-insensitively. Native endpoints require HTTPS, or HTTP on `localhost`, `127.0.0.1`, or `[::1]`, without user information, query, or fragment. The native connection retains its API path prefix.
84
+
85
+ Model metadata and defaults for custom connections remain native fx settings. The adapter does not invent context limits, protocols, or provider-specific capabilities. Anonymous custom connections are not represented by `api-key`; Anthropic Messages and generic Responses endpoints cannot be treated as Chat Completions. Native custom-connection vision limitations still apply even when metadata advertises image support.
86
+
87
+ Credential output slots cannot name process-control or routing variables such as `HOME`, `PATH`, `FX_PROVIDER`, `FX_MODEL`, `FX_AUTH_MODE`, loader/proxy controls, or native diagnostic/endpoint controls. Inapplicable access fields, malformed profiles, unknown connections, unsupported protocols, and unsafe slots fail before native startup. Both status and ACP use the same selected provider, model, and environment. Custom readiness checks the native provider name, endpoint, bearer slot metadata, and ACP provider/model selection; the generic status label `configured provider` alone is insufficient.
88
+
89
+ For all routes, inherited host-managed authentication, test endpoint overrides, competing Gateway credentials, and recording controls cannot replace the explicitly selected route. Native settings are fingerprinted around startup and before each task; a detected change requires a new session. This is not atomic protection against changes during a native request. Native permissions, approvals, same-session follow-ups, cancellation, and callback drain keep their existing behavior.
90
+
91
+ ## Gateway credential selection
92
+
93
+ The connection reads only the named variable from the selected file. Existing main-checkout and worktree path rules apply. For Gateway connections, the adapter supplies the selected credential through the fx subprocess environment, fixes the native provider to AI Gateway, and removes competing credential variables and endpoint overrides. It does not save the key in native settings or place it in process arguments. Native shell processes can inherit that environment, so the credential is available within the native process tree. ACP does not provide an isolated credential channel for this release. Credential isolation from native tools belongs to the external harness or execution environment; this adapter does not provide it.
49
94
 
50
95
  Native authentication preferences can override environment credentials. Startup runs native credential-source introspection with the same environment and requires the expected environment source. A known conflicting native login fails with `ACCESS_UNAVAILABLE` and guidance to select the environment source in fx. An unrecognized or malformed introspection result fails with `PROTOCOL_ERROR`, without trying another route. The adapter never changes native authentication preferences itself. It checks native settings for changes during startup and before each new task; detected changes fail with `INVALID_CONFIG` and require a new session. ACP does not provide atomic, in-process credential-source attestation, so native settings must remain stable while the session is active. OIDC project validation and token-lifetime rules are the same as for other Gateway connections.
51
96
 
package/sdk/harnesses.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Harnesses
2
2
 
3
- V1 integrates Codex, Claude Code, and fx. Grok Build, Cursor, and OpenCode remain product compatibility requirements without implemented adapters. Compatibility means connecting the external harness, not merely calling its model through an API.
3
+ V1 integrates Codex, Claude Code, fx, OpenCode, GitHub Copilot, and Cursor. Compatibility means connecting the external harness, not merely calling its model through an API.
4
4
 
5
5
  The library provides coordination and definitions. Harnesses own inference, native tools, conversation state, and context management. The execution environment provides any sandboxing or worktree isolation.
6
6
 
@@ -16,23 +16,23 @@ Automatic fallback ends at task submission. Execution failure, allowance exhaust
16
16
 
17
17
  ## Capabilities
18
18
 
19
- | Operation | Codex | Claude Code | fx |
20
- | --- | --- | --- | --- |
21
- | Native session follow-ups | Supported | Supported | Supported |
22
- | Queue between library tasks | Supported | Supported | Supported |
23
- | Active steering | Native steering | Uses interrupt semantics | Uses interrupt semantics |
24
- | Interruption | Native interruption with stop confirmation | Native interruption with stop confirmation | Native ACP cancellation with stop confirmation |
25
- | Custom tools | Native dynamic tools | Native SDK MCP tools | Private MCP HTTP tools |
26
- | Declared-child launcher permissions | Uses effective native permissions; no adapter-added rule | Session-only rules for the exact launcher and declared operations | Uses effective native permissions; no adapter-added rule |
27
- | Prompt-free recovery of failed work | Explicit unsupported result | Explicit unsupported result | Explicit unsupported result |
28
- | Startup readiness check without a turn | Supported | Supported | Supported |
19
+ | Operation | Codex | Claude Code | fx | OpenCode | Copilot | Cursor |
20
+ | --- | --- | --- | --- | --- | --- | --- |
21
+ | Native session follow-ups | Supported | Supported | Supported | Supported | Supported | Supported |
22
+ | Queue between library tasks | Supported | Supported | Supported | Supported | Supported | Supported |
23
+ | Active steering | Native steering | Uses interrupt semantics | Uses interrupt semantics | Uses interrupt semantics | Uses interrupt semantics | Uses interrupt semantics |
24
+ | Interruption | Native stop confirmation | Native stop confirmation | Native ACP stop confirmation | Native abort stop confirmation | Native abort stop confirmation | Native cancellation stop confirmation |
25
+ | Custom tools | Native dynamic tools | Native SDK MCP tools | Private MCP HTTP tools | Private MCP tools | Native SDK callbacks | Native SDK custom tools or subscription MCP tools |
26
+ | Declared-child launcher permissions | Effective native policy | Exact session-only launcher rules | Effective native policy | Effective native policy | Effective native policy | Effective native policy |
27
+ | Prompt-free recovery of failed work | Explicit unsupported result | Explicit unsupported result | Explicit unsupported result | Explicit unsupported result | Explicit unsupported result | Explicit unsupported result |
28
+ | Startup readiness check without a turn | Supported | Supported | Supported | Supported | Supported | Supported |
29
29
 
30
30
  `resume` remains a stable command; these adapters return `RECOVERY_UNSUPPORTED` when they cannot resume failed work without replay. The queue remains paused. Unsupported native steering follows the [interrupt contract](message-delivery.md), including cancellation propagation and a new replacement task; output reports the effective mode.
31
31
 
32
- All TypeScript constructors require a model. Direct [CLI harness targets](cli/index.md) may omit it to select and retain a verifiable native default within the authorized access route. Codex and Claude Code default fast mode to false. fx exposes model and optional native effort, with the capabilities and limits described in its [adapter contract](fx.md). Explicit options are validated where the native interface exposes compatibility. A provider can reject a request after submission; that is an execution failure, not permission to choose another model. Model/provider substitutions detected by an adapter are rejected.
32
+ All TypeScript constructors require a model. The Codex, Claude Code, and fx direct [CLI harness targets](cli/index.md) may omit it to select and retain a verifiable native default within the authorized access route. OpenCode, Copilot, and Cursor require an explicit CLI model and reject effort. Codex and Claude Code default fast mode to false. fx exposes model and optional native effort. Cursor additionally exposes its optional SDK sandbox mode for API-key access; explicit sandbox settings are unsupported for subscription ACP access. Explicit options are validated where the native interface exposes compatibility. A provider can reject a request after submission; that is an execution failure, not permission to choose another model. Model/provider substitutions detected by an adapter are rejected.
33
33
 
34
34
  Claude fast mode with subscription access is unavailable in v1 because shared agent configuration does not authorize additional subscription spending. Explicit paid API or Gateway access can request it where supported. Native subscription eligibility and provider distribution terms still apply; subscription login is not an account-wide spending cap.
35
35
 
36
- See [native adapter behavior](adapter-contract.md) for authentication isolation, native permissions, tool transport, and lifecycle details.
36
+ See [native adapter behavior](adapter-contract.md), [Additional native harnesses](additional-harnesses.md), [OpenCode](opencode.md), [Copilot](copilot.md), and [Cursor](cursor.md) for authentication isolation, native permissions, tool transport, and lifecycle details.
37
37
 
38
38
  Codex permission behavior is version- and environment-dependent. The adapter does not assume that an installed Codex version can accept session-scoped launcher rules. Explicit [permission options](permissions.md) select native sandbox and network settings; the adapter does not broaden them automatically. A native approval request therefore remains possible for declared-child delegation even though the child is authorized by the Subharness definition.
package/sdk/index.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SDK and CLI
2
2
 
3
- The CLI runs generic Codex, Claude Code, and fx agents without definition files. The optional TypeScript SDK defines reusable specialists on those same external harnesses. The CLI coordinates sessions, queues, follow-ups, and nested delegation in caller-supplied working directories.
3
+ The CLI runs generic Codex, Claude Code, fx, OpenCode, GitHub Copilot, and Cursor agents without definition files. The optional TypeScript SDK defines reusable specialists on those same external harnesses. The CLI coordinates sessions, queues, follow-ups, and nested delegation in caller-supplied working directories.
4
4
 
5
5
  - [Distribution](distribution.md): package identity, local installation, and release boundaries.
6
6
  - [Agent skill](agent-skill.md): the installable skill that teaches a coding agent to delegate with the CLI.
@@ -13,6 +13,7 @@ The CLI runs generic Codex, Claude Code, and fx agents without definition files.
13
13
  - [Harnesses](harnesses.md): selection, capabilities, and fallback boundaries.
14
14
  - [CLI](cli/index.md): commands and response waiting.
15
15
  - [Output](cli/output.md): compact text and typed JSONL records.
16
+ - [Error diagnostics](diagnostics.md): failure categories, safe context, and recovery guidance.
16
17
  - [Sessions](sessions.md): task identity, state, and recovery.
17
18
  - [Message delivery](message-delivery.md): queue, steer, interrupt, and cancellation.
18
19
  - [Subagents](plugins/sub-agents.md): nested delegation and context boundaries.
@@ -22,4 +23,4 @@ The CLI runs generic Codex, Claude Code, and fx agents without definition files.
22
23
 
23
24
  These documents describe the v1 contract. They do not authorize automatic conversation migration, a custom model harness, sandbox provisioning, or a separate pipeline-definition API.
24
25
 
25
- The [fx adapter](fx.md) connects native fx ACP sessions through explicit AI Gateway access. The [repository team](project-team.md) defines the roles used to develop this project.
26
+ The adapter contracts cover [fx](fx.md), [OpenCode](opencode.md), [GitHub Copilot](copilot.md), and [Cursor](cursor.md). The shared configuration for the three additional harnesses is defined in [Additional native harnesses](additional-harnesses.md). The [repository team](project-team.md) defines the roles used to develop this project.
@@ -0,0 +1,57 @@
1
+ # OpenCode adapter
2
+
3
+ The OpenCode adapter runs the installed `opencode` executable in native HTTP server mode on a private loopback endpoint. This adapter supports OpenCode 1.18.32. It checks the executable version before starting the server and rejects other or unverifiable versions with `INVALID_CONFIG`, because configuration isolation depends on that version's native switches. OpenCode owns inference, native tools, conversation state, and compaction. The public configuration and access routes are defined in [additional harnesses](additional-harnesses.md).
4
+
5
+ ## Direct API keys
6
+
7
+ An explicit `api-key` connection requires `provider` and `env`; `envFile` and `baseUrl` are optional. Supported single-key providers are `anthropic`, `openai`, `google`, `groq`, `openrouter`, `xai`, `mistral`, `cohere`, `opencode` (Zen), and `opencode-go` (Go). Provider IDs that require additional cloud identity, resource, or region settings are not represented by this single-key connection. Unknown providers fail explicitly instead of trying ambient credentials.
8
+
9
+ The agent model uses the exact native `provider/model` ID and its prefix must equal the connection's provider. OpenRouter model names may contain additional slashes. The installed native catalog must contain the exact model and compatible provider metadata; the adapter does not invent custom model metadata. An optional `baseUrl` overrides the selected catalog provider's endpoint. Without it, the pinned native SDK supplies that provider's endpoint. Startup verifies the explicit provider, token configuration, model, and any endpoint override without generation. Native default endpoints and SDK transformations are not remote executed-model attestation.
10
+
11
+ ```json
12
+ {
13
+ "access": {
14
+ "opencode": [{ "type": "api-key", "provider": "anthropic", "env": "ANTHROPIC_API_KEY" }]
15
+ }
16
+ }
17
+ ```
18
+
19
+ Direct keys retain private configuration, data, state, and cache directories. Only the chosen provider is enabled; its environment-key discovery is disabled and the selected key is supplied explicitly. Saved native auth and default auth plugins are excluded. Both the main and auxiliary model are pinned to the exact native model. Existing Gateway behavior remains available independently.
20
+
21
+ ## Native saved logins
22
+
23
+ A `subscription` connection requires `provider: "openai"`, `"github-copilot"`, or `"xai"`, selecting the corresponding built-in native OAuth integration. The user completes OpenCode's native login first. The model uses the same exact `provider/model` syntax as direct access, with a matching provider prefix. Saved API-key and well-known credentials are not treated as OAuth subscriptions. Plan names alone do not establish credential type or eligibility.
24
+
25
+ ```json
26
+ { "access": { "opencode": [{ "type": "subscription", "provider": "openai" }] } }
27
+ ```
28
+
29
+ This route intentionally uses OpenCode's native persistent XDG data directory because OpenCode stores and refreshes its login there. The native process can access its complete authentication store and persist normal native data, including session history and token refreshes. Subharness does not read, copy, synchronize, or rewrite the credential file. It does not perform login or logout. Config, state, and cache remain private; project/provider configuration discovery remains disabled. Only built-in authentication plugins are enabled, with the explicitly selected inference provider and pinned main/auxiliary model. The subscription route does not offer an endpoint override.
30
+
31
+ Readiness requires the selected connected provider's OAuth plugin configuration and the exact native model. A missing login is unavailable; ambiguous, malformed, or conflicting auth metadata is an error. Detection relies on this pinned release's native provider source and OAuth markers, without extracting tokens or pretending that every native fetch transformation is exposed as an endpoint. A known saved API-key route cannot silently replace the requested OAuth route. Closing removes only adapter-owned private state; it never removes or restores the native persistent data directory.
32
+
33
+ ## Gateway isolation
34
+
35
+ For Gateway connections, the public model is a Gateway `creator/model` identifier. The native provider is `vercel`; the adapter supplies the corresponding `vercel/creator/model` native selection. Startup uses a private configuration and private native state directories, enables only the Gateway provider, and pins the main and auxiliary model to the requested identifier. It disables native model fallback, project/provider configuration discovery, default plugins, automatic updates, and sharing so inherited provider configuration cannot change the selected billing route.
36
+
37
+ Repository instruction discovery is restored through the native `instructions` setting without importing repository provider configuration. Starting at the execution directory and stopping at the nearest Git worktree root, the adapter finds `AGENTS.md`, otherwise `CLAUDE.md`, otherwise `CONTEXT.md`, using the first filename category with matches. Matching ancestor files are passed as absolute native instruction paths. Outside Git, only the execution directory is searched. Native per-file instruction handling remains native. Subharness specialist instructions supplement the first task. Native configuration, plugins, and custom native agent definitions excluded by this isolation profile are not copied into the temporary state.
38
+
39
+ Residual home or machine-managed configuration that would still load outside the private directories must be checked before native startup. If it cannot be established compatible with the isolated profile, startup fails with `INVALID_CONFIG`; organizational policy is never bypassed using test-only environment overrides. Missing model metadata is also an error; the adapter does not invent context limits or image capabilities for unknown models.
40
+
41
+ Only the selected Gateway credential is supplied for inference. An API key and an OIDC token retain their distinct Gateway authentication modes; the adapter must not pass an OIDC token as an API key. Configuration files containing credentials have mode `0600` in an owner-only temporary directory. Credentials never appear in command arguments, native diagnostic output, or shared project files. Startup checks the effective provider, endpoint, model, and native configuration before admitting prompts, and rejects incompatible or unverifiable settings. Private files are removed on startup failure and normal close.
42
+
43
+ The server is bound to `127.0.0.1` with a random per-process password, and requests are scoped to the caller's directory. Startup requires health, provider/configuration discovery, and creation of an empty native session. No generation is used to verify readiness or quota. A missing executable is `HARNESS_UNAVAILABLE`; malformed native protocol data is `PROTOCOL_ERROR`.
44
+
45
+ ## Tools and permissions
46
+
47
+ Declared tools are exposed through a private authenticated loopback MCP endpoint. Arguments are validated before callbacks run. Text and image content are preserved through MCP. The adapter verifies that the native MCP connection succeeds before submitting work. Tools stop admitting calls during interruption and close, and admitted callbacks must settle before stop is reported.
48
+
49
+ Native permissions are configured to ask. Active native permission requests use the shared approval flow, exposing bounded action context and the native `once`/`reject` decisions. Reusable grants are not exposed because native instance scope can include native child sessions. Startup-time requests and other interactive questions fail with `INPUT_REQUIRED`; no permission is automatically granted. The adapter does not add launcher allow rules. Native denial is passed back to OpenCode without authorizing a replacement operation. OpenCode can retire other pending requests in the same session after a rejection; the adapter reconciles native pending requests and drops late answers to retired operations.
50
+
51
+ ## Lifecycle
52
+
53
+ Each Subharness session owns one native conversation and one native server. Follow-up tasks retain that conversation. Every prompt pins the requested provider/model; detectable changes are errors without replay. A task returns the final assistant text only after successful native completion. Native errors, unfinished responses, and malformed terminal data cannot count as success. The final text limit is 1 MiB.
54
+
55
+ Interruption requests native abort and confirms the active work stopped; an accepted HTTP abort request alone is insufficient. It also drains admitted tools and retires outstanding approvals, including when native work ended before interruption began. Native stop confirmation is bounded; that deadline does not limit already-admitted host callbacks, which must settle before interruption completes. Failure to confirm native termination produces `CANCELLATION_FAILED`, and no replacement prompt is admitted to still-running work. Steering uses the shared interrupt behavior; prompt-free recovery is unsupported.
56
+
57
+ Close aborts active work, closes event streams and the native session, terminates the owned server with bounded escalation when needed, and removes private configuration/state and tool endpoints. Startup failures use the same cleanup discipline. Normal cleanup never deletes project files or user-owned OpenCode settings.
@@ -1,6 +1,6 @@
1
1
  # Native Permissions
2
2
 
3
- Harness constructors accept optional native permission settings directly alongside model options. These settings configure the native session without modifying persistent native settings or creating a Subharness sandbox. Later supported native tool approvals are surfaced to the caller through the [structured approval flow](approvals.md); an explicit valid caller decision is required before authorization. The installed harness evaluates the selected policy, and the external execution environment enforces its remaining restrictions.
3
+ The Codex, Claude Code, and fx constructors accept optional native permission settings directly alongside model options. These settings configure the native session without modifying persistent native settings or creating a Subharness sandbox. OpenCode instead uses its isolated native ask policy, Copilot uses native manual permission mode, and neither exposes a public permission selector. Cursor exposes its documented SDK `sandboxMode` for API-key access; subscription ACP access rejects explicit sandbox settings and supports the documented once-only native approvals. Supported native tool approvals are surfaced to the caller through the [structured approval flow](approvals.md); an explicit valid caller decision is required before authorization. The installed harness evaluates the selected policy, and the external execution environment enforces its remaining restrictions.
4
4
 
5
5
  Omitted settings preserve native configuration. Explicit settings remain fixed for session follow-ups. A child uses its own definition and native configuration; it does not inherit the parent's explicit permission options. Invalid definitions fail before execution. Unsupported or observably rejected explicit settings fail without fallback to another harness or permission policy.
6
6
 
@@ -21,6 +21,8 @@ codex({
21
21
 
22
22
  `approvalPolicy: "never"` suppresses approval prompts; it does not grant operations blocked by the selected sandbox. `danger-full-access` removes Codex's native sandbox boundary, subject to external restrictions.
23
23
 
24
+ By default, `workspace-write` keeps `.git`, `.agents`, and `.codex` read-only inside the writable workspace. It also protects the Git directory named by a `.git` pointer file, even when that directory is inside the workspace; for a linked worktree, that directory is in the main checkout's Git directory and holds the worktree's index. Git index updates such as `git add` can therefore fail in ordinary checkouts and linked worktrees. subharness does not add writable roots or change the native policy to permit these operations.
25
+
24
26
  ## Claude Code
25
27
 
26
28
  ```ts
@@ -62,4 +64,4 @@ For a surfaced permission request, the caller inspects the action and responds t
62
64
 
63
65
  The caller reads the Subharness skill and prefers one ordinary `subharness run <target>` through known host background-command controls. It continues independent work and later collects that hosted command's output, which already contains the first response or terminal outcome. When those controls are unavailable or uncertain, it uses `run --detach`, retains the returned task and session identifiers, continues other work, and later collects the result with `wait`. `status` is optional when a snapshot or additional state is needed. Shell `&` and an unobserved process do not replace managed task records. Both paths require collecting the result and confirming its terminal outcome before reporting completion; detached admission alone is not completion.
64
66
 
65
- The native caller needs permission to execute the private launcher and reach the local coordinator. Each child needs permission for its own task. This remains true for Codex, Claude Code, and fx; no constructor option promises native desktop notifications or automatic chat reactivation.
67
+ The native caller needs permission to execute the private launcher and reach the local coordinator. Each child needs permission for its own task. This remains true for all six native harnesses; no constructor option promises native desktop notifications or automatic chat reactivation. OpenCode and Copilot can surface supported active permission requests through the structured approval flow. Cursor subscription sessions also expose supported once-only ACP permissions. Other Cursor interactive requests fail with `INPUT_REQUIRED`.
@@ -21,6 +21,8 @@ Role instructions alone do not grant native capabilities or permissions. Browsin
21
21
 
22
22
  The repository's Codex roles explicitly select `approvalPolicy: "never"`, `sandboxMode: "workspace-write"`, and `networkAccessEnabled: true` for local development and coordinator access. The reviewer selects Claude `permissionMode: "dontAsk"` with `Read`, `Glob`, `Grep`, and `Bash` allowed. Its read-only review responsibility remains an instruction; allowing Bash is not a filesystem read-only boundary. The fx roles explicitly select `permissionMode: "auto"`. These policies use [native permission options](permissions.md), preserve native restrictions, and do not guarantee that every operation is permitted. Protected paths and rejected automatic reviews can still require a lead-managed execution path.
23
23
 
24
+ Implementation roles return unstaged working-tree changes and verification evidence. Local Git staging and commits belong to the lead unless the assignment explicitly authorizes them. When an implementation task requires moving or deleting ordinary files, roles use filesystem operations; subsequent Git staging records the renames. By default, Codex workspace-write protects `.git`, `.agents`, and `.codex` inside the writable workspace. It also protects the Git directory named by a `.git` pointer file, even when that directory is inside the workspace; for a linked worktree, that directory is in the main checkout's Git directory and holds the worktree's index. A required change under those protected paths is reported with the exact operation, affected paths, and partial effects for lead-managed execution. A copied replacement does not complete a move while the original remains.
25
+
24
26
  ## Skills and task context
25
27
 
26
28
  Repository skills live in `.agents/skills/<name>/SKILL.md`. The short index in `AGENTS.md` explains when each skill applies. Agents read only the relevant skill and supporting references for their current task. Skill contents are not concatenated into every agent's instructions.
package/sdk/tools.md CHANGED
@@ -70,6 +70,6 @@ function toolResult(result: { readonly content: readonly ToolContent[] }): ToolR
70
70
 
71
71
  `ToolResult` is an opaque value created by `toolResult`; callers must return it directly from `execute`. It is not a JSON transport format. Content must be nonempty, contain only the supported block fields, and include at most eight images. Image data is canonical padded standard base64 without a data-URL prefix. The decoded file signature must match its declared MIME type. Each encoded image is limited to 5 MiB; the complete rich result's JSON content is limited to 8 MiB, and combined text is limited to 1 MiB. Ordinary text and JSON results retain their 1 MiB limit.
72
72
 
73
- The SDK validates rich results at the tool execution boundary. Malformed blocks report `TOOL_RESULT_INVALID`; exceeded limits report `TOOL_RESULT_TOO_LARGE`. Native adapters pass images as image content, never as base64 inside a text result: MCP image blocks for Claude Code and fx, and image content items for Codex. Model-specific image support and lower native limits still apply; a text-only model cannot perform visual inspection. The [fx contract](fx.md) records a native image-tool crash affecting fx 0.0.9. The tool author controls which files are read. This helper does not grant filesystem access or fetch remote images.
73
+ The SDK validates rich results at the tool execution boundary. Malformed blocks report `TOOL_RESULT_INVALID`; exceeded limits report `TOOL_RESULT_TOO_LARGE`. Native adapters pass images as image content, never as base64 inside a text result. Claude Code, fx, and OpenCode use MCP image blocks; Codex and Cursor SDK sessions use native image content items; Cursor subscription sessions use MCP image blocks. [Copilot](copilot.md) groups content by type in its native result envelope: text blocks are joined in their original text order, images retain their original image order as binary image results, and interleaving between the text and image groups is unavailable. Model-specific image support and lower native limits still apply; a text-only model cannot perform visual inspection. The [fx contract](fx.md) records a native image-tool crash affecting fx 0.0.9. The tool author controls which files are read. This helper does not grant filesystem access or fetch remote images.
74
74
 
75
75
  Cancellation waits for already-admitted callbacks to settle. There is no cancellation signal in `execute(input)`, and completed effects are not rolled back. Streaming tool results and arbitrary external tool-definition objects are outside this API.