@moretea-labs/forge 1.5.0-rc.1 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/AGENTS.md +9 -11
  2. package/CHANGELOG.md +27 -1
  3. package/CLAUDE.md +8 -10
  4. package/DESIGN.md +278 -0
  5. package/README.md +70 -90
  6. package/README.zh-CN.md +52 -55
  7. package/SKILL.md +8 -11
  8. package/THIRD_PARTY_NOTICES.md +9 -3
  9. package/assets/branding/README.md +4 -2
  10. package/assets/hooks/lib/workflow-state.sh +19 -18
  11. package/assets/hooks/post-edit-guard.sh +6 -75
  12. package/assets/hooks/prompt-guard.sh +24 -12
  13. package/assets/hooks/session-start-context.sh +17 -17
  14. package/assets/hooks/stop-orchestrator.sh +2 -2
  15. package/assets/partials/04-project-structure.partial.md +6 -6
  16. package/assets/partials/05-workflow.partial.md +6 -6
  17. package/assets/partials/07-footer.partial.md +1 -1
  18. package/assets/partials/08-orchestration.partial.md +2 -2
  19. package/assets/partials-agents/02-operating-mode.partial.md +5 -5
  20. package/assets/partials-agents/03-orchestration.partial.md +3 -3
  21. package/assets/partials-agents/04-task-protocol.partial.md +3 -3
  22. package/assets/partials-agents/08-deep-docs.partial.md +1 -1
  23. package/assets/reference-configs/agentic-development-flow.md +49 -86
  24. package/assets/reference-configs/external-tooling.md +21 -61
  25. package/assets/reference-configs/handoff-protocol.md +25 -20
  26. package/assets/reference-configs/harness-overview.md +8 -8
  27. package/assets/skill-version.json +2 -2
  28. package/assets/templates/helpers/archive-workflow.sh +0 -1
  29. package/assets/templates/helpers/capture-plan.sh +3 -3
  30. package/assets/templates/helpers/check-task-workflow.sh +2 -2
  31. package/assets/templates/helpers/codex-handoff-resume.sh +5 -5
  32. package/assets/templates/helpers/ensure-task-workflow.sh +37 -35
  33. package/assets/templates/helpers/new-plan.sh +1 -1
  34. package/assets/templates/helpers/plan-to-todo.sh +2 -2
  35. package/assets/templates/helpers/prepare-codex-handoff.sh +2 -2
  36. package/assets/templates/helpers/prepare-handoff.sh +9 -9
  37. package/assets/templates/helpers/refresh-current-status.sh +2 -2
  38. package/assets/templates/helpers/ship-worktrees.sh +1 -1
  39. package/assets/templates/helpers/sprint-backlog.sh +1 -1
  40. package/assets/templates/helpers/verify-sprint.sh +7 -7
  41. package/assets/templates/helpers/workstream-sync.sh +1 -1
  42. package/assets/templates/plan.template.md +1 -1
  43. package/assets/workflow-contract.v1.json +6 -3
  44. package/docs/architecture/current/README.md +10 -9
  45. package/docs/architecture/current/approved-target-architecture.zh-CN.md +2 -2
  46. package/docs/architecture/current/architecture-invariants.md +2 -2
  47. package/docs/architecture/current/automation-and-schedule-engine.md +15 -15
  48. package/docs/architecture/current/codegraph-context-provider.md +2 -2
  49. package/docs/architecture/current/control-plane-authority-inventory.md +12 -0
  50. package/docs/architecture/current/dispatch-and-agent-strategy.md +11 -11
  51. package/docs/architecture/current/entity-model.md +0 -27
  52. package/docs/architecture/current/failure-recovery.md +0 -24
  53. package/docs/architecture/current/governance.md +1 -1
  54. package/docs/architecture/current/implementation-status.md +1 -1
  55. package/docs/architecture/current/legacy-governance.md +58 -0
  56. package/docs/architecture/current/multi-repository-execution.md +1 -1
  57. package/docs/architecture/current/peer-supercontroller-runtime.md +1 -1
  58. package/docs/architecture/current/personal-assistant-plugin-baseline.md +4 -5
  59. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -10
  60. package/docs/architecture/current/target-requirements-traceability.md +2 -2
  61. package/docs/architecture/current/thin-harness-governance-policy.md +1 -1
  62. package/docs/architecture/current/thin-harness-v1.md +9 -11
  63. package/docs/architecture/domains/runtime-harness.md +1 -1
  64. package/docs/forge-autonomous-goal-loop.md +3 -1
  65. package/docs/forge-chatgpt-mcp-setup.md +67 -176
  66. package/docs/images/forge-banner-cn.svg +26 -1
  67. package/docs/images/forge-banner.svg +26 -1
  68. package/docs/operations/features.md +1 -1
  69. package/docs/operations/homebrew.md +3 -3
  70. package/docs/operations/mcp-tool-exposure.md +5 -5
  71. package/docs/operations/platform-support.md +45 -37
  72. package/docs/operations/platform-support.zh-CN.md +40 -38
  73. package/docs/operations/releasing.md +3 -3
  74. package/docs/operations/releasing.zh-CN.md +3 -3
  75. package/docs/operations/troubleshooting.md +11 -6
  76. package/docs/operations/troubleshooting.zh-CN.md +11 -6
  77. package/docs/public-usage-guide.md +28 -21
  78. package/docs/public-usage-guide.zh-CN.md +28 -21
  79. package/docs/tutorials/01-install-and-start.md +58 -35
  80. package/docs/tutorials/01-install-and-start.zh-CN.md +58 -35
  81. package/docs/tutorials/02-connect-chatgpt.md +118 -46
  82. package/docs/tutorials/02-connect-chatgpt.zh-CN.md +119 -45
  83. package/docs/wiki/Architecture.md +1 -1
  84. package/docs/wiki/Installation.md +2 -2
  85. package/docs/wiki/Quick-Start.md +1 -1
  86. package/docs/wiki/Work-Lifecycle.md +1 -1
  87. package/install.ps1 +4 -5
  88. package/install.sh +4 -6
  89. package/package.json +15 -5
  90. package/scripts/archive-workflow.sh +0 -1
  91. package/scripts/benchmark-thin-harness-mcp-e2e.ts +27 -14
  92. package/scripts/build-controller-ui.ts +28 -0
  93. package/scripts/capture-plan.sh +4 -4
  94. package/scripts/check-agent-tooling.sh +12 -1
  95. package/scripts/check-platform-support.mjs +2 -2
  96. package/scripts/check-public-docs.sh +16 -5
  97. package/scripts/check-release-readiness.sh +5 -11
  98. package/scripts/check-runtime-architecture.mjs +14 -22
  99. package/scripts/check-tarball-install-smoke.sh +3 -2
  100. package/scripts/check-task-workflow.sh +2 -2
  101. package/scripts/codex-handoff-resume.sh +5 -5
  102. package/scripts/create-project-dirs.sh +3 -3
  103. package/scripts/ensure-task-workflow.sh +45 -35
  104. package/scripts/init-project.sh +4 -4
  105. package/scripts/install-desktop-operator-registration.ts +2 -2
  106. package/scripts/lib/project-init-lib.sh +46 -44
  107. package/scripts/migrate-project-template.sh +7 -4
  108. package/scripts/new-plan.sh +1 -1
  109. package/scripts/plan-to-todo.sh +2 -2
  110. package/scripts/prepare-codex-handoff.sh +2 -2
  111. package/scripts/prepare-handoff.sh +9 -9
  112. package/scripts/refresh-current-status.sh +2 -2
  113. package/scripts/setup-plugins.sh +3 -3
  114. package/scripts/ship-worktrees.sh +1 -1
  115. package/scripts/sprint-backlog.sh +5 -5
  116. package/scripts/sync-codex-installed-copies.sh +2 -3
  117. package/scripts/verify-sprint.sh +7 -7
  118. package/scripts/workstream-sync.sh +1 -1
  119. package/src/cli/chatgpt-browser/bridge-extension.ts +1 -1
  120. package/src/cli/chatgpt-browser/bridge-provider.ts +29 -0
  121. package/src/cli/chatgpt-browser/file-policy.ts +3 -1
  122. package/src/cli/commands/chatgpt.ts +51 -0
  123. package/src/cli/commands/doctor.ts +1 -1
  124. package/src/cli/commands/init-hook.ts +213 -70
  125. package/src/cli/commands/init.ts +5 -6
  126. package/src/cli/commands/mcp.ts +31 -5
  127. package/src/cli/commands/runtime.ts +61 -8
  128. package/src/cli/commands/setup-profile.ts +472 -0
  129. package/src/cli/controller/check-runner.ts +20 -3
  130. package/src/cli/controller/codex-continuation.ts +4 -7
  131. package/src/cli/controller/context-pack.ts +118 -14
  132. package/src/cli/controller/operational-plan.ts +4 -4
  133. package/src/cli/controller/task-ledger.ts +10 -10
  134. package/src/cli/controller/work-mode.ts +6 -13
  135. package/src/cli/index.ts +14 -35
  136. package/src/cli/local-bridge/connector-freshness.ts +1 -1
  137. package/src/cli/local-bridge/console-assets.ts +17 -0
  138. package/src/cli/local-bridge/console-automations.ts +160 -0
  139. package/src/cli/local-bridge/dashboard.ts +8 -1303
  140. package/src/cli/local-bridge/facade-api.ts +16 -7
  141. package/src/cli/local-bridge/frontend/src/App.tsx +10 -0
  142. package/src/cli/local-bridge/frontend/src/components/Button.tsx +1 -0
  143. package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +3 -0
  144. package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +1 -0
  145. package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +1 -0
  146. package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +1 -0
  147. package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +3 -0
  148. package/src/cli/local-bridge/frontend/src/design/icons.tsx +11 -0
  149. package/src/cli/local-bridge/frontend/src/design/tokens.css +8 -0
  150. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +3 -0
  151. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +4 -0
  152. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +3 -0
  153. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +2 -0
  154. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +2 -0
  155. package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +2 -0
  156. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +3 -0
  157. package/src/cli/local-bridge/frontend/src/lib/api.ts +23 -0
  158. package/src/cli/local-bridge/frontend/src/lib/format.ts +4 -0
  159. package/src/cli/local-bridge/frontend/src/lib/routes.ts +7 -0
  160. package/src/cli/local-bridge/frontend/src/main.tsx +1 -0
  161. package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +1 -0
  162. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +2 -0
  163. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +3 -0
  164. package/src/cli/local-bridge/frontend/src/styles.css +12 -0
  165. package/src/cli/local-bridge/frontend/src/types.ts +14 -0
  166. package/src/cli/local-bridge/frontend/src/vite-env.d.ts +1 -0
  167. package/src/cli/local-bridge/frontend/vite.config.ts +27 -0
  168. package/src/cli/local-bridge/server.ts +45 -0
  169. package/src/cli/local-bridge/ui-dist/app.css +1 -0
  170. package/src/cli/local-bridge/ui-dist/app.js +11094 -0
  171. package/src/cli/mcp/auth.ts +2 -0
  172. package/src/cli/mcp/instructions.ts +3 -3
  173. package/src/cli/mcp/legacy-tool-service.ts +27 -23
  174. package/src/cli/mcp/multi-repository.ts +2 -0
  175. package/src/cli/mcp/policy.ts +7 -5
  176. package/src/cli/mcp/repository-tools.ts +53 -14
  177. package/src/cli/mcp/server.ts +5 -10
  178. package/src/cli/mcp/setup.ts +220 -276
  179. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  180. package/src/cli/mcp/toolset-names.ts +1 -1
  181. package/src/cli/mcp/toolset.ts +0 -1
  182. package/src/cli/mcp/transports/http.ts +51 -4
  183. package/src/cli/repositories/branch-name-policy.ts +0 -7
  184. package/src/cli/repositories/controller-home.ts +110 -3
  185. package/src/cli/repositories/safe-patch.ts +1 -1
  186. package/src/cli/repositories/selected-path-actions.ts +26 -24
  187. package/src/core/adoption/gitignore-plan.ts +2 -3
  188. package/src/core/adoption/plan.ts +4 -1
  189. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +556 -0
  190. package/src/runtime/control-plane/execution/work-handle-store.ts +128 -1
  191. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +277 -0
  192. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +169 -0
  193. package/src/runtime/control-plane/facade/capability-registry.ts +0 -10
  194. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +44 -25
  195. package/src/runtime/control-plane/facade/suggested-actions.ts +7 -1
  196. package/src/runtime/control-plane/facade/types.ts +0 -1
  197. package/src/runtime/control-plane/global-scheduler/scheduler.ts +30 -8
  198. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +114 -0
  199. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +175 -0
  200. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +161 -0
  201. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +64 -0
  202. package/src/runtime/control-plane/launcher/thin-launcher.ts +117 -24
  203. package/src/runtime/control-plane/routing/route-policy.ts +14 -14
  204. package/src/runtime/control-plane/runtime-cleanup.ts +0 -1
  205. package/src/runtime/evidence/event-ledger.ts +1 -1
  206. package/src/runtime/{workflow/campaigns/workspace.ts → execution/managed-workspace.ts} +41 -43
  207. package/src/runtime/execution/process-runtime/check-facade.ts +6 -0
  208. package/src/runtime/execution/process-runtime/check-result.ts +45 -0
  209. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +42 -16
  210. package/src/runtime/execution/process-runtime/command-facade.ts +4 -2
  211. package/src/runtime/execution/process-runtime/gc.ts +1 -1
  212. package/src/runtime/execution/process-runtime/index.ts +3 -0
  213. package/src/runtime/execution/process-runtime/interactive-admission.ts +14 -5
  214. package/src/runtime/execution/process-runtime/persisted-check.ts +285 -0
  215. package/src/runtime/execution/process-runtime/resource-claims.ts +30 -0
  216. package/src/runtime/execution/process-runtime/runtime.ts +18 -1
  217. package/src/runtime/execution/process-runtime/store.ts +1 -19
  218. package/src/runtime/execution/process-runtime/types.ts +4 -0
  219. package/src/runtime/execution/thin-harness/execution-router.ts +0 -1
  220. package/src/runtime/execution/thin-harness/fast-executor.ts +1 -1
  221. package/src/runtime/execution/thin-harness/lightweight-lanes.ts +1 -2
  222. package/src/runtime/execution/thin-harness/types.ts +0 -1
  223. package/src/runtime/execution/workers/executor.ts +1 -1
  224. package/src/runtime/gateway/mcp/execution-tools.ts +1 -1
  225. package/src/runtime/gateway/mcp/persisted-check-process.ts +3 -255
  226. package/src/runtime/gateway/mcp/process-tools.ts +16 -3
  227. package/src/runtime/gateway/mcp/resource-policy.ts +0 -9
  228. package/src/runtime/gateway/mcp/router.ts +117 -182
  229. package/src/runtime/gateway/mcp/runtime-tools.ts +331 -409
  230. package/src/runtime/gateway/mcp/work-validation-reconciler.ts +1 -219
  231. package/src/runtime/plugins/browser-adapter.ts +5 -0
  232. package/src/runtime/plugins/desktop-operator-registration.ts +1 -1
  233. package/src/runtime/plugins/store.ts +14 -6
  234. package/src/runtime/plugins/types.ts +1 -1
  235. package/src/runtime/projections/materialized-view.ts +1 -23
  236. package/src/runtime/recovery/maintenance-executor.ts +9 -0
  237. package/src/runtime/resources/ownership.ts +0 -1
  238. package/src/runtime/root/gateway-adapter.ts +2 -0
  239. package/src/runtime/root/mcp-transport.ts +10 -2
  240. package/src/runtime/root/package-connector-service.ts +136 -0
  241. package/src/runtime/root/package-runtime-release.ts +161 -0
  242. package/src/runtime/root/package-runtime-service.ts +185 -0
  243. package/src/runtime/root/release-materialize.ts +19 -0
  244. package/src/runtime/root/runtime.ts +2 -1
  245. package/src/runtime/root/scheduler.ts +5 -0
  246. package/src/runtime/root/service.ts +18 -5
  247. package/src/runtime/standalone-recovery/core.ts +65 -16
  248. package/src/runtime/workflow/findings/store.ts +145 -106
  249. package/src/runtime/workflow/findings/types.ts +22 -0
  250. package/src/runtime/workflow/schedules/engine.ts +132 -2
  251. package/src/runtime/workflow/schedules/pending-activation.ts +139 -0
  252. package/src/runtime/workflow/schedules/work-continuation.ts +218 -0
  253. package/docs/CHANGELOG.md +0 -978
  254. package/docs/README.zh-CN.md +0 -58
  255. package/scripts/smoke-chatgpt-supervised-automation.ts +0 -208
  256. package/src/cli/commands/controller.ts +0 -680
  257. package/src/runtime/workflow/campaigns/cleanup.ts +0 -263
  258. package/src/runtime/workflow/campaigns/engine.ts +0 -112
  259. package/src/runtime/workflow/campaigns/normalize.ts +0 -100
  260. package/src/runtime/workflow/campaigns/review.ts +0 -315
  261. package/src/runtime/workflow/campaigns/store.ts +0 -526
  262. package/src/runtime/workflow/campaigns/supervisor.ts +0 -112
  263. package/src/runtime/workflow/campaigns/types.ts +0 -290
  264. /package/src/runtime/{workflow/campaigns → execution}/workspace-agent.ts +0 -0
@@ -21,6 +21,8 @@ export interface McpLocalConfig {
21
21
  chatgpt?: {
22
22
  serverName?: string;
23
23
  endpoint?: string;
24
+ /** Loopback OAuth MCP endpoint used by ChatGPT tunnels/connectors. */
25
+ localEndpoint?: string;
24
26
  };
25
27
  profile?: string;
26
28
  toolset?: 'core' | 'advanced' | 'full';
@@ -10,11 +10,11 @@ export function mcpServerInstructions(profile: McpProfileName): string {
10
10
  return [
11
11
  ...common,
12
12
  'Use the shortest valid execution path. Investigation or parallelism alone must not create durable Work, Issues, Plans, Agents, isolation, or worktrees; escalate only for actual recovery, dependency, risk, scope, external-effect, or long-running requirements.',
13
- 'For bounded work, gather only task-relevant context once, then act through the exposed surface. When an exact code path is unknown, use rh_context(operation=search) once as the default code retrieval router, then read_repository_file for exact current ranges; do not fall back to shell grep unless retrieval is unavailable or raw Git semantics are explicitly needed. CodeGraph is optional structural augmentation behind rh_context.search for planning/debugging, not a default Direct-edit latency tax. The low-level search_repository handler is compatibility/internal surface, not a second default search path. Prefer repository_command_execute for ordinary local Git and shell operations, repository_safe_patch_apply for bounded source changes, and rh_work only when the task genuinely requires durable orchestration.',
13
+ 'For bounded implementation, use rh_context(operation=search, retrieval_mode=implementation) once as the default code retrieval router when the exact path is unknown. Its current raw snippets and file SHA identities are valid implementation evidence; ChatGPT decides semantic sufficiency and should request wider exact ranges only when impact ambiguity, truncation, drift, or an expansion signal can materially change the edit. For cross-cutting state/time/schema/cache/API/event/concurrency changes, ChatGPT should select relevant impact_domains in that first search so Forge expands those evidence dimensions mechanically in the same call; Forge never infers that the selected domains are semantically complete. Use retrieval_mode=plan|debug|review when the task intentionally needs a broader evidence surface. Do not fall back to shell grep unless retrieval is unavailable or raw Git semantics are explicitly needed. The low-level search_repository handler is compatibility/internal surface, not a second default search path. Prefer repository_command_execute for ordinary local Git and shell operations, repository_safe_patch_apply for bounded source changes, and rh_work only when the task genuinely requires durable orchestration.',
14
14
  'Do not preflight unrelated Git history, prior Work, plugins, permissions, TCC, browser mode, maintenance, or recovery state. Inspect them only when the requested operation depends on them or a real failure points there.',
15
15
  'Run independent reads, searches, diagnostics, checks, repositories, checkouts, and tasks concurrently by default. Serialize only on a real dependency or Resource Claim conflict, and reuse existing projections, process handles, and check evidence instead of repeating successful observations.',
16
- 'Validation must be proportional to the change: run focused checks first and expand only when risk or failure evidence justifies it. Do not perform maintenance or deep runtime diagnosis before ordinary work unless execution is actually blocked.',
17
- 'After a bounded successful change, finish the requested delivery directly. Avoid additional investigation whose result cannot change implementation or acceptance, and do not invoke hidden atomic compatibility tools merely because they exist in the full profile.',
16
+ 'Validation must be proportional to the change: cheap patch-safety checks belong to every coherent edit batch, focused tests run after that batch is stable, and expensive full-suite checks belong at candidate/release or explicitly high-risk boundaries. When a Direct Edit batch is stable, repository_safe_patch_apply may receive explicit check_ids to start revision-bound validation; omit check_ids during intermediate edits. Long checks return managed Processes: continue independent read/review work, then use validation_only with the returned edit-session/validation ids as the synchronization join instead of polling repeatedly. Do not perform maintenance or deep runtime diagnosis before ordinary work unless execution is actually blocked.',
17
+ 'repository_safe_patch_apply returns bounded edit-session diff evidence for semantic review. Review that evidence directly instead of issuing a mandatory follow-up diff/status call; expand it only when truncated or semantically ambiguous. After a bounded successful change, finish the requested delivery directly. Avoid additional investigation whose result cannot change implementation or acceptance, and do not invoke hidden atomic compatibility tools merely because they exist in the full profile.',
18
18
  ].join(' ');
19
19
  }
20
20
  if (profile === 'orchestrator') {
@@ -164,6 +164,8 @@ export interface McpToolContext {
164
164
  sessionId?: string;
165
165
  /** Authenticated or controller-issued principal used to scope session state. */
166
166
  principalId?: string;
167
+ /** Authenticated transport controller/provider type. */
168
+ controllerType?: 'chatgpt' | 'codex' | 'claude' | 'grok' | 'human';
167
169
  controllerInstanceId?: string;
168
170
  /** Bound repository identity for session cache keys. */
169
171
  repoId?: string;
@@ -790,7 +792,9 @@ function workflowFileCandidates(repoRoot: string): string[] {
790
792
  "plans",
791
793
  "tasks",
792
794
  ".ai/context",
793
- ".ai/harness/handoff",
795
+ ".ai/harness/session",
796
+ ".ai/harness/controller/packets",
797
+ ".ai/harness/projections",
794
798
  ".ai/harness/checks",
795
799
  ];
796
800
  const files: string[] = [];
@@ -1466,8 +1470,8 @@ export function buildMcpToolDefinitions(
1466
1470
  annotations: readOnly,
1467
1471
  },
1468
1472
  {
1469
- name: "latest_handoff",
1470
- description: "Return latest forge handoff artifacts.",
1473
+ name: "latest_session_context",
1474
+ description: "Return the latest rebuildable Forge session continuation context.",
1471
1475
  inputSchema: EMPTY_SCHEMA,
1472
1476
  annotations: readOnly,
1473
1477
  },
@@ -1530,14 +1534,14 @@ export function buildMcpToolDefinitions(
1530
1534
  {
1531
1535
  name: "prepare_codex_goal_from_sprint",
1532
1536
  description:
1533
- "Prepare .ai/harness/handoff/codex-goal.md and a host-native /goal prompt from PRD + checklist Sprint.",
1537
+ "Prepare .ai/harness/controller/packets/codex-goal.md and a host-native /goal prompt from PRD + checklist Sprint.",
1534
1538
  inputSchema: goalFromSprintSchema,
1535
1539
  annotations: write,
1536
1540
  },
1537
1541
  {
1538
1542
  name: "write_codex_goal",
1539
1543
  description:
1540
- "Write .ai/harness/handoff/codex-goal.md after required section validation.",
1544
+ "Write .ai/harness/controller/packets/codex-goal.md after required section validation.",
1541
1545
  inputSchema: {
1542
1546
  type: "object",
1543
1547
  properties: {
@@ -1550,8 +1554,8 @@ export function buildMcpToolDefinitions(
1550
1554
  annotations: write,
1551
1555
  },
1552
1556
  {
1553
- name: "append_handoff_note",
1554
- description: "Append a timestamped planner handoff note.",
1557
+ name: "append_controller_plan_note",
1558
+ description: "Append a timestamped ChatGPT planning note to the controller packet cache.",
1555
1559
  inputSchema: {
1556
1560
  type: "object",
1557
1561
  properties: { actor: { type: "string" }, body: { type: "string" } },
@@ -1616,7 +1620,7 @@ export function buildMcpToolDefinitions(
1616
1620
  type: "object",
1617
1621
  properties: {
1618
1622
  description: { type: "string" },
1619
- mode: { type: "string", enum: ["direct", "plan", "debug", "review", "campaign", "release", "scale", "-direct", "-plan", "-debug", "-review", "-campaign", "-release", "-scale"] },
1623
+ mode: { type: "string", enum: ["direct", "plan", "debug", "review", "release", "scale", "-direct", "-plan", "-debug", "-review", "-release", "-scale"] },
1620
1624
  known_paths: { type: "array", items: { type: "string" } },
1621
1625
  expected_files: { type: "number" },
1622
1626
  expected_changed_lines: { type: "number" },
@@ -2147,7 +2151,7 @@ export function buildMcpToolDefinitions(
2147
2151
  type: "object",
2148
2152
  properties: {
2149
2153
  description: { type: "string" },
2150
- mode: { type: "string", enum: ["direct", "plan", "debug", "review", "campaign", "release", "scale", "-direct", "-plan", "-debug", "-review", "-campaign", "-release", "-scale"] },
2154
+ mode: { type: "string", enum: ["direct", "plan", "debug", "review", "release", "scale", "-direct", "-plan", "-debug", "-review", "-release", "-scale"] },
2151
2155
  known_paths: { type: "array", items: { type: "string" } },
2152
2156
  expected_files: { type: "number" },
2153
2157
  expected_changed_lines: { type: "number" },
@@ -2996,7 +3000,9 @@ export async function callMcpTool(
2996
3000
  "docs/spec.md",
2997
3001
  "plans",
2998
3002
  "tasks/current.md",
2999
- ".ai/harness/handoff",
3003
+ ".ai/harness/session",
3004
+ ".ai/harness/controller/packets",
3005
+ ".ai/harness/projections",
3000
3006
  ".ai/harness/checks",
3001
3007
  ];
3002
3008
  audit(ctx, name, "ok", args);
@@ -3174,7 +3180,7 @@ export async function callMcpTool(
3174
3180
  },
3175
3181
  toolExposure: {
3176
3182
  preferred: preferredTools,
3177
- note: "Prefer the five rh_* workflow facades for orchestration. Typed repository, Git, Issue/Task, Campaign, plugin, browser, iOS, artifact, and recovery tools remain available because the current MCP transport cannot load domain schemas per conversation.",
3183
+ note: "Prefer the five rh_* workflow facades for orchestration. Typed repository, Git, Issue/Task, plugin, browser, iOS, artifact, and recovery tools remain available because the current MCP transport cannot load domain schemas per conversation.",
3178
3184
  advanced: expectedTools.filter((tool) => !preferredTools.includes(tool)).slice(0, 40),
3179
3185
  compatibilityRetained: true,
3180
3186
  },
@@ -5055,12 +5061,10 @@ export async function callMcpTool(
5055
5061
  redactions: payload.redactions,
5056
5062
  });
5057
5063
  }
5058
- case "latest_handoff": {
5064
+ case "latest_session_context": {
5059
5065
  const paths = [
5060
- ".ai/harness/handoff/resume.md",
5061
- ".ai/harness/handoff/controller-current.md",
5062
- ".ai/harness/handoff/codex-goal.md",
5063
- ".ai/harness/handoff/chatgpt-plan.md",
5066
+ ".ai/harness/session/resume.md",
5067
+ ".ai/harness/session/continuation.md",
5064
5068
  ];
5065
5069
  const handoff = paths.map((path) => {
5066
5070
  const decision = resolveMcpPath(
@@ -5085,7 +5089,7 @@ export async function callMcpTool(
5085
5089
  };
5086
5090
  });
5087
5091
  audit(ctx, name, "ok", args);
5088
- return textResult({ handoff });
5092
+ return textResult({ sessionContext: handoff });
5089
5093
  }
5090
5094
  case "latest_checks": {
5091
5095
  const files = workflowFileCandidates(ctx.repoRoot)
@@ -5269,7 +5273,7 @@ export async function callMcpTool(
5269
5273
  name,
5270
5274
  "blocked",
5271
5275
  args,
5272
- ".ai/harness/handoff/codex-goal.md",
5276
+ ".ai/harness/controller/packets/codex-goal.md",
5273
5277
  `missing required goal sections: ${missing.join(", ")}`,
5274
5278
  );
5275
5279
  return errorResult(
@@ -5281,7 +5285,7 @@ export async function callMcpTool(
5281
5285
  return writeMarkdownArtifact(
5282
5286
  ctx,
5283
5287
  name,
5284
- ".ai/harness/handoff/codex-goal.md",
5288
+ ".ai/harness/controller/packets/codex-goal.md",
5285
5289
  "Codex Goal",
5286
5290
  "codex-goal",
5287
5291
  goal.body,
@@ -5301,7 +5305,7 @@ export async function callMcpTool(
5301
5305
  name,
5302
5306
  "blocked",
5303
5307
  args,
5304
- ".ai/harness/handoff/codex-goal.md",
5308
+ ".ai/harness/controller/packets/codex-goal.md",
5305
5309
  `missing required goal sections: ${missing.join(", ")}`,
5306
5310
  );
5307
5311
  return errorResult(
@@ -5313,7 +5317,7 @@ export async function callMcpTool(
5313
5317
  return writeMarkdownArtifact(
5314
5318
  ctx,
5315
5319
  name,
5316
- ".ai/harness/handoff/codex-goal.md",
5320
+ ".ai/harness/controller/packets/codex-goal.md",
5317
5321
  "Codex Goal",
5318
5322
  "codex-goal",
5319
5323
  body,
@@ -5321,8 +5325,8 @@ export async function callMcpTool(
5321
5325
  args,
5322
5326
  );
5323
5327
  }
5324
- case "append_handoff_note": {
5325
- const path = ".ai/harness/handoff/chatgpt-plan.md";
5328
+ case "append_controller_plan_note": {
5329
+ const path = ".ai/harness/controller/packets/chatgpt-plan.md";
5326
5330
  const decision = resolveMcpPath(
5327
5331
  ctx.repoRoot,
5328
5332
  path,
@@ -31,6 +31,7 @@ export interface McpServerOptions {
31
31
  toolset?: McpToolset | string;
32
32
  sessionId?: string;
33
33
  principalId?: string;
34
+ controllerType?: McpToolContext['controllerType'];
34
35
  controllerInstanceId?: string;
35
36
  /** Canonical Runtime source authority. Internal Runtime MCP only; never an execution repository. */
36
37
  runtimeSourceRoot?: string;
@@ -359,6 +360,7 @@ export function createMcpToolContext(opts: McpServerOptions): MultiRepositoryMcp
359
360
  enableChatgptBrowser: opts.enableChatgptBrowser === true,
360
361
  sessionId: opts.sessionId,
361
362
  principalId: opts.principalId,
363
+ controllerType: opts.controllerType,
362
364
  controllerInstanceId: opts.controllerInstanceId,
363
365
  runtimeSourceRoot: opts.runtimeSourceRoot,
364
366
  };
@@ -35,7 +35,9 @@ export const PLANNER_READ_GLOBS = [
35
35
  'tasks/reviews/**',
36
36
  'tasks/notes/**',
37
37
  '.ai/context/**',
38
- '.ai/harness/handoff/**',
38
+ '.ai/harness/session/**',
39
+ '.ai/harness/controller/packets/**',
40
+ '.ai/harness/projections/**',
39
41
  '.ai/harness/checks/**',
40
42
  ];
41
43
 
@@ -43,8 +45,8 @@ export const PLANNER_WRITE_GLOBS = [
43
45
  'plans/prds/**',
44
46
  'plans/sprints/**',
45
47
  'plans/plan-*.md',
46
- '.ai/harness/handoff/codex-goal.md',
47
- '.ai/harness/handoff/chatgpt-plan.md',
48
+ '.ai/harness/controller/packets/codex-goal.md',
49
+ '.ai/harness/controller/packets/chatgpt-plan.md',
48
50
  ];
49
51
 
50
52
  export interface McpPolicyOptions {
@@ -164,7 +166,7 @@ export function getMcpPolicy(profile: McpProfileName, opts: McpPolicyOptions = {
164
166
  return applyPolicyOverrides({
165
167
  profile,
166
168
  readGlobs: ['plans/**', 'tasks/**', 'docs/spec.md', '.ai/context/**', '.ai/harness/**'],
167
- writeGlobs: ['tasks/reviews/**', '.ai/harness/checks/**', '.ai/harness/handoff/**'],
169
+ writeGlobs: ['tasks/reviews/**', '.ai/harness/checks/**', '.ai/harness/session/**', '.ai/harness/controller/packets/**'],
168
170
  denyGlobs: COMMON_DENY_GLOBS,
169
171
  maxFileBytes: 512 * 1024,
170
172
  execution: executionPolicy({
@@ -207,7 +209,7 @@ export function getMcpPolicy(profile: McpProfileName, opts: McpPolicyOptions = {
207
209
  const devRunner = opts.devAgentRunner === true;
208
210
  return applyPolicyOverrides({
209
211
  profile,
210
- readGlobs: devRunner ? ['.ai/harness/handoff/codex-goal.md'] : [],
212
+ readGlobs: devRunner ? ['.ai/harness/controller/packets/codex-goal.md'] : [],
211
213
  writeGlobs: [],
212
214
  denyGlobs: devRunner ? COMMON_DENY_GLOBS : ['**'],
213
215
  maxFileBytes: devRunner ? 512 * 1024 : 0,
@@ -19,6 +19,7 @@ import {
19
19
  } from '../repositories/registry';
20
20
  import { buildControllerWorkbench } from '../repositories/workbench';
21
21
  import { applySafePatch, buildSafePatchPlan } from '../repositories/safe-patch';
22
+ import { getEditSessionDiff } from '../editing/edit-session';
22
23
  import { buildSyncOperationDigest, classifyUserFacingError } from '../../runtime/control-plane/facade/operation-digest';
23
24
  import { diagnoseRepositoryStuckState, listRepositoryGoalRuns, readRepositoryGoalRegistry, runRepositoryGoal, upsertRepositoryGoal } from '../repositories/goal-registry';
24
25
  import {
@@ -50,6 +51,7 @@ import {
50
51
  import { assessWorkMode, parseExplicitTaskMode } from '../controller/work-mode';
51
52
  import type { CallToolResult, McpToolDefinition } from './tools';
52
53
  import {
54
+ boundUtf8,
53
55
  compactCommandOutput,
54
56
  compactErrorMessage,
55
57
  compactRoutingSummary,
@@ -136,7 +138,7 @@ export const repositoryToolDefinitions: McpToolDefinition[] = [
136
138
  operation: {
137
139
  type: 'string',
138
140
  enum: ['summary', 'batch_execute', 'lanes_execute', 'lanes_integrate', 'fast_receipt_get', 'fast_receipt_list', 'execution_route', 'assess_work_mode'],
139
- description: 'Defaults to summary. Use batch_execute for multi-step Fast Path (one parent receipt). Use lanes_execute for limited parallel reads. Use assess_work_mode for Fast/Durable/Campaign routing advice.',
141
+ description: 'Defaults to summary. Use batch_execute for multi-step Fast Path (one parent receipt). Use lanes_execute for limited parallel reads. Use assess_work_mode for Fast/Durable routing advice.',
140
142
  },
141
143
  payload: {
142
144
  type: 'object',
@@ -235,20 +237,25 @@ export const repositoryToolDefinitions: McpToolDefinition[] = [
235
237
  operations: { type: 'array', items: { type: 'object' }, description: 'Edit operations using the same shape as apply_patch.' },
236
238
  chunk_size: { type: 'number', description: 'Maximum operations per deterministic chunk. Capped at 100.' },
237
239
  }, ['operations'], true),
238
- definition('repository_safe_patch_apply', 'Apply a deterministic chunked repository patch through edit sessions, refreshing missing file fingerprints before each chunk. Defaults to synchronous interactive apply.', {
240
+ definition('repository_safe_patch_apply', 'Apply one coherent deterministic edit batch and return bounded review evidence. Checks are opt-in: pass check_ids only when the batch is stable. Long checks return managed Process handles instead of blocking the MCP call; use validation_only with the returned session/request ids to join later without replaying the patch.', {
239
241
  repo_id: repoId,
240
242
  checkout_id: { type: 'string', description: 'Optional checkout identity for repositories with multiple local clones.' },
241
- session_id: { type: 'string', description: 'Existing edit session id. Omit to create one.' },
243
+ session_id: { type: 'string', description: 'Existing edit session id. Required for validation_only; otherwise omit to create one.' },
242
244
  purpose: { type: 'string', description: 'Purpose for a newly created edit session.' },
243
- operations: { type: 'array', items: { type: 'object' }, description: 'Edit operations using the same shape as apply_patch. create/write create parent dirs as needed.' },
245
+ operations: { type: 'array', items: { type: 'object' }, description: 'Edit operations using the same shape as apply_patch. Required unless validation_only=true.' },
244
246
  chunk_size: { type: 'number', description: 'Maximum operations per deterministic chunk. Capped at 100.' },
245
247
  expected_revision: { type: 'number', description: 'Expected starting edit-session revision.' },
246
248
  allowed_paths: { type: 'array', items: { type: 'string' }, description: 'Optional allowed path globs for a newly created session.' },
247
249
  continue_on_error: { type: 'boolean', description: 'Continue applying later independent chunks after a failed chunk. Defaults to false.' },
248
250
  refresh_fingerprints: { type: 'boolean', description: 'Refresh file fingerprints before every chunk. Defaults to true.' },
249
251
  recover_stale_session: { type: 'boolean', description: 'For new sessions, recover stale edit-session fingerprints into a fresh session. Defaults to true.' },
250
- apply_mode: { type: 'string', enum: ['sync', 'async'], description: 'Defaults to sync for interactive development. Set async to queue a durable Job.' },
251
- }, ['operations']),
252
+ check_ids: { type: 'array', items: { type: 'string' }, description: 'Optional focused validation for this stable coherent edit batch. Omit to edit without running tests.' },
253
+ check_timeout_ms: { type: 'number', description: 'Per-check execution budget. Long checks still return managed handles immediately.' },
254
+ lease_wait_ms: { type: 'number', description: 'Bounded resource-lease wait for conflicting validation lanes.' },
255
+ validation_request_id: { type: 'string', description: 'Stable validation identity returned by a prior edit+validation call; reuse with validation_only to join without replaying edits.' },
256
+ validation_only: { type: 'boolean', description: 'When true, do not edit. Reconcile/reuse the existing session validation Processes identified by session_id/check_ids/validation_request_id.' },
257
+ apply_mode: { type: 'string', enum: ['sync', 'async'], description: 'Defaults to sync for interactive development. Set async only for a separately durable operation.' },
258
+ }),
252
259
  definition('repository_command_preview', 'Preview one repository-scoped local command with classification, approval token, and Git snapshots.', {
253
260
  repo_id: repoId,
254
261
  checkout_id: { type: 'string', description: 'Optional checkout identity for repositories with multiple local clones.' },
@@ -688,7 +695,6 @@ export async function callRepositoryTool(
688
695
  reasons: assessment.reasons,
689
696
  recommendedMode: assessment.recommendedMode,
690
697
  issueRequired: assessment.issueRequired,
691
- campaignRequired: assessment.campaignRequired,
692
698
  },
693
699
  nextTools: assessment.nextTools,
694
700
  });
@@ -833,6 +839,27 @@ export async function callRepositoryTool(
833
839
  ];
834
840
  const ok = applied.status === 'applied';
835
841
  const firstFailure = applied.failures?.[0];
842
+ const editDiff = applied.appliedChunks.length > 0
843
+ ? getEditSessionDiff(repository.canonicalRoot, applied.session.sessionId)
844
+ : undefined;
845
+ const boundedEditDiff = editDiff
846
+ ? boundUtf8(editDiff.patch, RESPONSE_BUDGET.inlineOutputBytes)
847
+ : undefined;
848
+ const reviewEvidence = editDiff && boundedEditDiff
849
+ ? {
850
+ source: 'edit_session' as const,
851
+ sessionId: editDiff.sessionId,
852
+ revision: editDiff.revision,
853
+ sha256: editDiff.sha256,
854
+ patchPreview: boundedEditDiff.text,
855
+ truncated: boundedEditDiff.truncated,
856
+ byteLength: boundedEditDiff.byteLength,
857
+ semanticReviewAuthority: 'chatgpt' as const,
858
+ next: boundedEditDiff.truncated
859
+ ? 'The edit diff exceeds the inline budget. Expand only the affected ranges or diff needed for semantic review.'
860
+ : 'Review this exact edit-session diff before deciding whether more edits or focused validation are needed.',
861
+ }
862
+ : undefined;
836
863
  const digest = buildSyncOperationDigest({
837
864
  ok,
838
865
  operation: 'repository_safe_patch_apply',
@@ -859,6 +886,7 @@ export async function callRepositoryTool(
859
886
  terminal: true,
860
887
  applyMode: 'sync',
861
888
  digest,
889
+ ...(reviewEvidence ? { reviewEvidence } : {}),
862
890
  suggestedNextActions: digest.suggestedNextActions,
863
891
  };
864
892
  return ok ? result(payload) : { ...result(payload), isError: true };
@@ -900,24 +928,31 @@ export async function callRepositoryTool(
900
928
  // nested ExecutionJob. Local Job remains the worker settlement surface.
901
929
  const fromDurableWorker = args.__from_durable_worker === true
902
930
  || typeof args.__execution_job_id === 'string';
903
- // Thin Harness: short readonly / focused-check commands skip Local Job when eligible.
904
- const forceDurable = fromDurableWorker
905
- || args.apply_mode === 'async'
906
- || args.mode === 'durable'
931
+ // Process Runtime owns local async execution. apply_mode=async means
932
+ // return its Process handle immediately; it must not promote a local
933
+ // command into the retired ExecutionJob path. Explicit mode=durable
934
+ // remains a separate external-Controller boundary.
935
+ const returnHandleImmediately = args.apply_mode === 'async'
936
+ || args.mode === 'async'
907
937
  || args.async === true
908
938
  || args.background === true;
939
+ const forceDurable = fromDurableWorker
940
+ || args.mode === 'durable'
941
+ || args.force_durable === true;
909
942
  const routingDecision = routeExecution({
910
943
  operation: 'repository_command_execute',
911
944
  mode: forceDurable ? 'durable' : args.mode === 'fast' ? 'fast' : 'auto',
912
945
  command: args.command as string | string[] | undefined,
913
946
  timeoutMs,
914
- background: args.background === true || args.async === true,
947
+ background: forceDurable && (args.background === true || args.async === true),
915
948
  defaultBranch: repository.defaultBranch,
916
949
  approvalContinuation: typeof args.approval_request_id === 'string'
917
950
  || typeof args.approval_token === 'string',
918
951
  });
919
952
  // Unified Process Runtime for local commands (Direct/Managed) when not forced durable.
920
- if (!forceDurable && !fromDurableWorker) {
953
+ // Ephemeral workspaces cannot persist a recoverable async Process handle,
954
+ // so their async requests remain promotion-required below.
955
+ if (!forceDurable && !fromDurableWorker && !(target.workspace && returnHandleImmediately)) {
921
956
  try {
922
957
  const routeClass = classifyRepositoryCommandRoute(args.command as string | string[], {
923
958
  forceDurable: false,
@@ -931,7 +966,11 @@ export async function callRepositoryTool(
931
966
  command: args.command as string | string[],
932
967
  cwd: typeof args.cwd === 'string' ? args.cwd : undefined,
933
968
  timeoutMs,
969
+ interactiveWaitMs: returnHandleImmediately
970
+ ? 0
971
+ : typeof args.interactive_wait_ms === 'number' ? args.interactive_wait_ms : undefined,
934
972
  maxOutputBytes,
973
+ returnHandleImmediately,
935
974
  requestId: typeof args.request_id === 'string' ? args.request_id : undefined,
936
975
  executionIdentity,
937
976
  allowNonGitWorkspace: target.workspace !== undefined,
@@ -1040,7 +1079,7 @@ export async function callRepositoryTool(
1040
1079
  return failure(error);
1041
1080
  }
1042
1081
  }
1043
- if (target.workspace && forceDurable) {
1082
+ if (target.workspace && (forceDurable || returnHandleImmediately)) {
1044
1083
  return result({
1045
1084
  accepted: false,
1046
1085
  mode: 'durable',
@@ -219,17 +219,12 @@ async function proxyRuntimeToolCall(
219
219
  ctx: MultiRepositoryMcpToolContext,
220
220
  name: string,
221
221
  args: Record<string, unknown>,
222
- expectedSchema?: CanonicalRuntimeToolSchema,
223
222
  ): Promise<CallToolResult> {
224
223
  return withCanonicalRuntimeClient(ctx, async (client) => {
225
- if (expectedSchema) {
226
- const listed = await client.listTools();
227
- const definitions = listed.tools as Tool[];
228
- const fingerprint = forgeToolSurfaceFingerprint(definitions);
229
- if (fingerprint !== expectedSchema.fingerprint || !definitions.some((tool) => tool.name === name)) {
230
- return toolSurfaceMismatchResult();
231
- }
232
- }
224
+ // The outer Connector session is already bound to the Canonical Runtime
225
+ // schema and fenced by the Runtime-published fingerprint before dispatch.
226
+ // Re-listing tools here creates a second discovery round trip for every
227
+ // tool call without strengthening that fence.
233
228
  const response = await client.callTool({ name, arguments: args });
234
229
  return response as unknown as CallToolResult;
235
230
  });
@@ -309,7 +304,7 @@ export function createForgeMcpServerFromContext(
309
304
  // Gateway processes from acquiring Process Runtime leases or evaluating
310
305
  // Runtime source coherence against their own checkout.
311
306
  if (!getRuntimeWriteClaim()) {
312
- if (runtimeSchema) return proxyRuntimeToolCall(ctx, name, args, runtimeSchema);
307
+ if (runtimeSchema) return proxyRuntimeToolCall(ctx, name, args);
313
308
  if (observeRuntimeStatus(ctx.controllerHome).ready) return proxyRuntimeToolCall(ctx, name, args);
314
309
  }
315
310
  const accessResult = callAccessTool(ctx, name, args);