harnery 0.30.0 → 0.31.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 (517) hide show
  1. package/README.md +4 -4
  2. package/dist/commander.d.ts +8 -0
  3. package/dist/commander.d.ts.map +1 -1
  4. package/dist/commander.js +14 -13
  5. package/dist/commands/adapter.d.ts +12 -0
  6. package/dist/commands/adapter.d.ts.map +1 -0
  7. package/dist/commands/{harness.js → adapter.js} +35 -35
  8. package/dist/commands/agents.d.ts +3 -2
  9. package/dist/commands/agents.d.ts.map +1 -1
  10. package/dist/commands/agents.js +185 -74
  11. package/dist/commands/artifacts.d.ts +4 -0
  12. package/dist/commands/artifacts.d.ts.map +1 -0
  13. package/dist/commands/artifacts.js +143 -0
  14. package/dist/commands/backup.d.ts +1 -1
  15. package/dist/commands/backup.d.ts.map +1 -1
  16. package/dist/commands/backup.js +5 -2
  17. package/dist/commands/browse.d.ts.map +1 -1
  18. package/dist/commands/browse.js +310 -7
  19. package/dist/commands/checkpoint.d.ts +12 -0
  20. package/dist/commands/checkpoint.d.ts.map +1 -0
  21. package/dist/commands/checkpoint.js +162 -0
  22. package/dist/commands/context.d.ts +2 -2
  23. package/dist/commands/context.d.ts.map +1 -1
  24. package/dist/commands/context.js +3 -151
  25. package/dist/commands/decision.d.ts.map +1 -1
  26. package/dist/commands/decision.js +31 -7
  27. package/dist/commands/deinit.d.ts +2 -2
  28. package/dist/commands/deinit.js +15 -15
  29. package/dist/commands/doctor.js +23 -23
  30. package/dist/commands/governor.d.ts +4 -0
  31. package/dist/commands/governor.d.ts.map +1 -0
  32. package/dist/commands/{supervisor.js → governor.js} +133 -108
  33. package/dist/commands/grep.d.ts +1 -1
  34. package/dist/commands/grep.d.ts.map +1 -1
  35. package/dist/commands/grep.js +19 -2
  36. package/dist/commands/init.d.ts +12 -12
  37. package/dist/commands/init.d.ts.map +1 -1
  38. package/dist/commands/init.js +44 -30
  39. package/dist/commands/{session.d.ts → journal.d.ts} +2 -2
  40. package/dist/commands/journal.d.ts.map +1 -0
  41. package/dist/commands/{scratch.js → journal.js} +47 -47
  42. package/dist/commands/policy.js +1 -1
  43. package/dist/commands/presence.js +2 -2
  44. package/dist/commands/sync.d.ts +1 -1
  45. package/dist/commands/sync.js +3 -3
  46. package/dist/commands/tunnel.d.ts +16 -0
  47. package/dist/commands/tunnel.d.ts.map +1 -1
  48. package/dist/commands/tunnel.js +213 -27
  49. package/dist/commands/web-fetch.js +1 -1
  50. package/dist/commands/web.d.ts +19 -0
  51. package/dist/commands/web.d.ts.map +1 -1
  52. package/dist/commands/web.js +51 -0
  53. package/dist/commands/work.d.ts.map +1 -1
  54. package/dist/commands/work.js +38 -22
  55. package/dist/commands/workflow.d.ts.map +1 -1
  56. package/dist/commands/workflow.js +35 -28
  57. package/dist/core/{harnesses → adapters}/attest-projection.d.ts +2 -2
  58. package/dist/core/adapters/attest-projection.d.ts.map +1 -0
  59. package/dist/core/{harnesses → adapters}/attest.d.ts +16 -16
  60. package/dist/core/adapters/attest.d.ts.map +1 -0
  61. package/dist/core/{harnesses → adapters}/attest.js +9 -9
  62. package/dist/core/{harnesses → adapters}/attestation.d.ts +16 -16
  63. package/dist/core/adapters/attestation.d.ts.map +1 -0
  64. package/dist/core/{harnesses → adapters}/attestation.js +20 -20
  65. package/dist/core/{harnesses → adapters}/bench.d.ts +12 -12
  66. package/dist/core/adapters/bench.d.ts.map +1 -0
  67. package/dist/core/{harnesses → adapters}/bench.js +12 -12
  68. package/dist/core/adapters/index.d.ts +13 -0
  69. package/dist/core/adapters/index.d.ts.map +1 -0
  70. package/dist/core/adapters/index.js +6 -0
  71. package/dist/core/{harnesses → adapters}/profiles.d.ts +11 -11
  72. package/dist/core/adapters/profiles.d.ts.map +1 -0
  73. package/dist/core/{harnesses → adapters}/profiles.js +11 -11
  74. package/dist/core/adapters/registry.d.ts +15 -0
  75. package/dist/core/adapters/registry.d.ts.map +1 -0
  76. package/dist/core/{harnesses → adapters}/registry.js +11 -11
  77. package/dist/core/{harnesses → adapters}/types.d.ts +23 -23
  78. package/dist/core/adapters/types.d.ts.map +1 -0
  79. package/dist/core/{harnesses → adapters}/types.js +1 -1
  80. package/dist/core/agents/canonical-emit.d.ts +9 -14
  81. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  82. package/dist/core/agents/canonical-emit.js +15 -44
  83. package/dist/core/agents/cli-emit.js +1 -1
  84. package/dist/core/agents/cli.js +30 -26
  85. package/dist/core/agents/codex-replay.d.ts +1 -1
  86. package/dist/core/agents/codex-replay.js +6 -6
  87. package/dist/core/agents/coord-bin.d.ts +33 -0
  88. package/dist/core/agents/coord-bin.d.ts.map +1 -0
  89. package/dist/core/agents/coord-bin.js +89 -0
  90. package/dist/core/agents/coord-client.d.ts +78 -8
  91. package/dist/core/agents/coord-client.d.ts.map +1 -1
  92. package/dist/core/agents/coord-client.js +303 -75
  93. package/dist/core/agents/events/consume.d.ts +1 -1
  94. package/dist/core/agents/events/emit.d.ts +5 -6
  95. package/dist/core/agents/events/emit.d.ts.map +1 -1
  96. package/dist/core/agents/events/emit.js +2 -2
  97. package/dist/core/agents/paths.d.ts +5 -2
  98. package/dist/core/agents/paths.d.ts.map +1 -1
  99. package/dist/core/agents/paths.js +7 -13
  100. package/dist/core/agents/render/prompt-context.d.ts +21 -9
  101. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  102. package/dist/core/agents/render/prompt-context.js +82 -30
  103. package/dist/core/agents/render/session-context.d.ts +1 -1
  104. package/dist/core/agents/render/session-context.js +5 -5
  105. package/dist/core/agents/rules/claim-conflict.d.ts +2 -6
  106. package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
  107. package/dist/core/agents/rules/claim-conflict.js +1 -1
  108. package/dist/core/agents/rules/commit-conflict.js +98 -22
  109. package/dist/core/agents/rules/stop-hook.d.ts +9 -9
  110. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  111. package/dist/core/agents/rules/stop-hook.js +23 -5
  112. package/dist/core/agents/rules/verdict.d.ts +14 -0
  113. package/dist/core/agents/rules/verdict.d.ts.map +1 -0
  114. package/dist/core/agents/rules/verdict.js +1 -0
  115. package/dist/core/agents/session-events.js +3 -3
  116. package/dist/core/agents/state/council.d.ts +1 -1
  117. package/dist/core/agents/state/council.js +1 -1
  118. package/dist/core/agents/state/heartbeat-projector.d.ts +3 -2
  119. package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
  120. package/dist/core/agents/state/heartbeat-projector.js +14 -10
  121. package/dist/core/agents/state/heartbeat-writer.d.ts +1 -1
  122. package/dist/core/agents/state/heartbeat-writer.js +12 -12
  123. package/dist/core/agents/state/{scratch.d.ts → journal.d.ts} +7 -7
  124. package/dist/core/agents/state/{scratch.d.ts.map → journal.d.ts.map} +1 -1
  125. package/dist/core/agents/state/{scratch.js → journal.js} +12 -12
  126. package/dist/core/agents/state/pidmap.d.ts +28 -4
  127. package/dist/core/agents/state/pidmap.d.ts.map +1 -1
  128. package/dist/core/agents/state/pidmap.js +130 -15
  129. package/dist/core/agents/state/proc-start.d.ts +95 -0
  130. package/dist/core/agents/state/proc-start.d.ts.map +1 -0
  131. package/dist/core/agents/state/proc-start.js +199 -0
  132. package/dist/core/agents/state/shell-mutation.d.ts +1 -1
  133. package/dist/core/agents/state/shell-mutation.js +1 -1
  134. package/dist/core/agents/state/stale-sweep.js +7 -7
  135. package/dist/core/artifacts/index.d.ts +86 -0
  136. package/dist/core/artifacts/index.d.ts.map +1 -0
  137. package/dist/core/artifacts/index.js +421 -0
  138. package/dist/core/config.d.ts +9 -2
  139. package/dist/core/config.d.ts.map +1 -1
  140. package/dist/core/config.js +26 -2
  141. package/dist/core/context/index.d.ts +12 -12
  142. package/dist/core/context/index.js +10 -10
  143. package/dist/core/governor/adapter-spread.d.ts +52 -0
  144. package/dist/core/governor/adapter-spread.d.ts.map +1 -0
  145. package/dist/core/governor/adapter-spread.js +52 -0
  146. package/dist/core/governor/index.d.ts +7 -0
  147. package/dist/core/governor/index.d.ts.map +1 -0
  148. package/dist/core/governor/index.js +6 -0
  149. package/dist/core/governor/plan-api.d.ts +38 -0
  150. package/dist/core/governor/plan-api.d.ts.map +1 -0
  151. package/dist/core/governor/plan-api.js +83 -0
  152. package/dist/core/governor/plan-read.d.ts +5 -0
  153. package/dist/core/governor/plan-read.d.ts.map +1 -0
  154. package/dist/core/{supervisor → governor}/plan-read.js +66 -52
  155. package/dist/core/{supervisor → governor}/plan-types.d.ts +57 -56
  156. package/dist/core/governor/plan-types.d.ts.map +1 -0
  157. package/dist/core/{supervisor → governor}/plan-types.js +4 -4
  158. package/dist/core/governor/planning.d.ts +48 -0
  159. package/dist/core/governor/planning.d.ts.map +1 -0
  160. package/dist/core/{supervisor → governor}/planning.js +125 -94
  161. package/dist/core/governor/read.d.ts +6 -0
  162. package/dist/core/governor/read.d.ts.map +1 -0
  163. package/dist/core/governor/read.js +4 -0
  164. package/dist/core/governor/runner.d.ts +37 -0
  165. package/dist/core/governor/runner.d.ts.map +1 -0
  166. package/dist/core/{supervisor → governor}/runner.js +15 -15
  167. package/dist/core/governor/service-read.d.ts +6 -0
  168. package/dist/core/governor/service-read.d.ts.map +1 -0
  169. package/dist/core/{supervisor → governor}/service-read.js +12 -12
  170. package/dist/core/governor/service.d.ts +114 -0
  171. package/dist/core/governor/service.d.ts.map +1 -0
  172. package/dist/core/{supervisor → governor}/service.js +57 -57
  173. package/dist/core/governor/state.d.ts +116 -0
  174. package/dist/core/governor/state.d.ts.map +1 -0
  175. package/dist/core/{supervisor → governor}/state.js +228 -108
  176. package/dist/core/hooks/adapter/detect.d.ts +9 -0
  177. package/dist/core/hooks/{harness → adapter}/detect.d.ts.map +1 -1
  178. package/dist/core/hooks/{harness → adapter}/detect.js +8 -8
  179. package/dist/core/hooks/{harness → adapter}/events.d.ts +15 -14
  180. package/dist/core/hooks/adapter/events.d.ts.map +1 -0
  181. package/dist/core/hooks/{harness → adapter}/events.js +5 -5
  182. package/dist/core/hooks/{harness → adapter}/output.d.ts +20 -14
  183. package/dist/core/hooks/adapter/output.d.ts.map +1 -0
  184. package/dist/core/hooks/{harness → adapter}/output.js +30 -22
  185. package/dist/core/hooks/{harness → adapter}/parse.d.ts +5 -5
  186. package/dist/core/hooks/{harness → adapter}/parse.d.ts.map +1 -1
  187. package/dist/core/hooks/{harness → adapter}/parse.js +4 -4
  188. package/dist/core/hooks/{harness → adapter}/wiring.d.ts +15 -15
  189. package/dist/core/hooks/{harness → adapter}/wiring.d.ts.map +1 -1
  190. package/dist/core/hooks/{harness → adapter}/wiring.js +13 -13
  191. package/dist/core/hooks/cli.d.ts +3 -3
  192. package/dist/core/hooks/cli.js +187 -162
  193. package/dist/core/hooks/effects/image-capture.d.ts +5 -5
  194. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  195. package/dist/core/hooks/effects/image-capture.js +3 -3
  196. package/dist/core/hooks/effects/index.d.ts +12 -12
  197. package/dist/core/hooks/effects/index.d.ts.map +1 -1
  198. package/dist/core/hooks/effects/index.js +19 -19
  199. package/dist/core/hooks/events/emit.d.ts +2 -2
  200. package/dist/core/hooks/events/emit.d.ts.map +1 -1
  201. package/dist/core/hooks/events/emit.js +1 -1
  202. package/dist/core/hooks/events/rotate.js +1 -1
  203. package/dist/core/hooks/events/schema.d.ts +13 -5
  204. package/dist/core/hooks/events/schema.d.ts.map +1 -1
  205. package/dist/core/hooks/guard-path.d.ts +2 -2
  206. package/dist/core/hooks/guard-path.js +2 -2
  207. package/dist/core/hooks/index.d.ts +1 -1
  208. package/dist/core/hooks/index.d.ts.map +1 -1
  209. package/dist/core/hooks/resolve/anchor.d.ts +14 -5
  210. package/dist/core/hooks/resolve/anchor.d.ts.map +1 -1
  211. package/dist/core/hooks/resolve/anchor.js +64 -7
  212. package/dist/core/hooks/resolve/coord-root.d.ts +16 -11
  213. package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
  214. package/dist/core/hooks/resolve/coord-root.js +18 -43
  215. package/dist/core/hooks/resolve/intent.js +1 -1
  216. package/dist/core/hooks/resolve/owner.d.ts +1 -1
  217. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  218. package/dist/core/hooks/resolve/owner.js +11 -5
  219. package/dist/core/{scratch → journal}/index.d.ts +25 -25
  220. package/dist/core/{scratch → journal}/index.d.ts.map +1 -1
  221. package/dist/core/{scratch → journal}/index.js +38 -38
  222. package/dist/core/policy/evaluate.d.ts +1 -1
  223. package/dist/core/policy/evaluate.d.ts.map +1 -1
  224. package/dist/core/policy/evaluate.js +7 -7
  225. package/dist/core/policy/types.d.ts +3 -3
  226. package/dist/core/policy/types.d.ts.map +1 -1
  227. package/dist/core/work/state.d.ts +12 -4
  228. package/dist/core/work/state.d.ts.map +1 -1
  229. package/dist/core/work/state.js +50 -17
  230. package/dist/core/workflow/adapters.d.ts +17 -0
  231. package/dist/core/workflow/adapters.d.ts.map +1 -0
  232. package/dist/core/workflow/adapters.js +21 -0
  233. package/dist/core/workflow/approvals.js +6 -6
  234. package/dist/core/workflow/billing.d.ts +9 -9
  235. package/dist/core/workflow/billing.js +9 -9
  236. package/dist/core/workflow/child-env.d.ts +10 -2
  237. package/dist/core/workflow/child-env.d.ts.map +1 -1
  238. package/dist/core/workflow/child-env.js +12 -4
  239. package/dist/core/workflow/engine.d.ts +15 -5
  240. package/dist/core/workflow/engine.d.ts.map +1 -1
  241. package/dist/core/workflow/engine.js +138 -83
  242. package/dist/core/workflow/evidence-preflight.d.ts +24 -0
  243. package/dist/core/workflow/evidence-preflight.d.ts.map +1 -0
  244. package/dist/core/workflow/evidence-preflight.js +134 -0
  245. package/dist/core/workflow/index.d.ts +1 -1
  246. package/dist/core/workflow/index.d.ts.map +1 -1
  247. package/dist/core/workflow/proof.d.ts +11 -5
  248. package/dist/core/workflow/proof.d.ts.map +1 -1
  249. package/dist/core/workflow/proof.js +45 -36
  250. package/dist/core/workflow/run-state.d.ts +1 -1
  251. package/dist/core/workflow/run-state.js +7 -7
  252. package/dist/core/workflow/sandbox-projection.d.ts +6 -6
  253. package/dist/core/workflow/sandbox-projection.d.ts.map +1 -1
  254. package/dist/core/workflow/sandbox-projection.js +11 -11
  255. package/dist/core/workflow/spawn-claude.d.ts +3 -3
  256. package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
  257. package/dist/core/workflow/spawn-claude.js +9 -6
  258. package/dist/core/workflow/spawn-codex.d.ts +4 -4
  259. package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
  260. package/dist/core/workflow/spawn-codex.js +9 -6
  261. package/dist/core/workflow/spawn-cursor.d.ts +4 -4
  262. package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
  263. package/dist/core/workflow/spawn-cursor.js +9 -6
  264. package/dist/core/workflow/spawn-failure.d.ts +1 -1
  265. package/dist/core/workflow/spawn-failure.js +1 -1
  266. package/dist/core/workflow/specialists.js +2 -2
  267. package/dist/core/workflow/{journal.d.ts → transcript.d.ts} +8 -8
  268. package/dist/core/workflow/transcript.d.ts.map +1 -0
  269. package/dist/core/workflow/{journal.js → transcript.js} +14 -14
  270. package/dist/core/workflow/types.d.ts +98 -51
  271. package/dist/core/workflow/types.d.ts.map +1 -1
  272. package/dist/core/workflow/types.js +11 -1
  273. package/dist/core/workflow/validate.d.ts +1 -1
  274. package/dist/core/workflow/validate.js +1 -1
  275. package/dist/core/workflow/workspaces/cancellation.js +2 -2
  276. package/dist/core/workflow/workspaces/cleanup.js +2 -2
  277. package/dist/core/workflow/workspaces/execution.js +6 -6
  278. package/dist/core/workflow/workspaces/inspect.js +9 -9
  279. package/dist/core/workflow/workspaces/integration.js +14 -14
  280. package/dist/core/workflow/workspaces/lifecycle.d.ts +1 -1
  281. package/dist/core/workflow/workspaces/lifecycle.d.ts.map +1 -1
  282. package/dist/core/workflow/workspaces/lifecycle.js +9 -9
  283. package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
  284. package/dist/core/workflow/workspaces/local-git.js +39 -5
  285. package/dist/core/workflow/workspaces/recovery.js +3 -3
  286. package/dist/core/workflow/workspaces/state.d.ts +1 -1
  287. package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
  288. package/dist/core/workflow/workspaces/state.js +3 -3
  289. package/dist/core/workflow/workspaces/types.d.ts +1 -1
  290. package/dist/core/workflow/workspaces/types.d.ts.map +1 -1
  291. package/dist/lib/browser/asserts.d.ts +28 -0
  292. package/dist/lib/browser/asserts.d.ts.map +1 -0
  293. package/dist/lib/browser/asserts.js +152 -0
  294. package/dist/lib/browser/client.d.ts +49 -0
  295. package/dist/lib/browser/client.d.ts.map +1 -1
  296. package/dist/lib/browser/client.js +155 -14
  297. package/dist/lib/browser/content-checks.d.ts +108 -0
  298. package/dist/lib/browser/content-checks.d.ts.map +1 -0
  299. package/dist/lib/browser/content-checks.js +474 -0
  300. package/dist/lib/browser/critique.d.ts +91 -0
  301. package/dist/lib/browser/critique.d.ts.map +1 -0
  302. package/dist/lib/browser/critique.js +167 -0
  303. package/dist/lib/browser/geometry.d.ts +32 -0
  304. package/dist/lib/browser/geometry.d.ts.map +1 -1
  305. package/dist/lib/browser/geometry.js +244 -1
  306. package/dist/lib/browser/index.d.ts +4 -1
  307. package/dist/lib/browser/index.d.ts.map +1 -1
  308. package/dist/lib/browser/index.js +2 -0
  309. package/dist/lib/claude-desktop.d.ts.map +1 -1
  310. package/dist/lib/claude-desktop.js +4 -1
  311. package/dist/lib/context/index.js +9 -2
  312. package/dist/lib/council/index.d.ts +6 -6
  313. package/dist/lib/council/index.d.ts.map +1 -1
  314. package/dist/lib/council/index.js +8 -8
  315. package/dist/lib/identities/assume.d.ts +2 -2
  316. package/dist/lib/identities/assume.js +7 -7
  317. package/dist/lib/instructions/apply.d.ts +3 -3
  318. package/dist/lib/instructions/apply.d.ts.map +1 -1
  319. package/dist/lib/instructions/apply.js +75 -27
  320. package/dist/lib/instructions/host-addendum.d.ts +54 -0
  321. package/dist/lib/instructions/host-addendum.d.ts.map +1 -0
  322. package/dist/lib/instructions/host-addendum.js +107 -0
  323. package/dist/lib/instructions/templates.d.ts +10 -3
  324. package/dist/lib/instructions/templates.d.ts.map +1 -1
  325. package/dist/lib/instructions/templates.js +41 -12
  326. package/dist/lib/machine.d.ts +2 -2
  327. package/dist/lib/machine.js +2 -2
  328. package/package.json +26 -21
  329. package/schemas/config.schema.json +26 -1
  330. package/src/commander.ts +22 -13
  331. package/src/commands/{harness.ts → adapter.ts} +46 -46
  332. package/src/commands/agents.ts +200 -78
  333. package/src/commands/artifacts.ts +168 -0
  334. package/src/commands/backup.ts +47 -33
  335. package/src/commands/browse.ts +438 -2
  336. package/src/commands/checkpoint.ts +196 -0
  337. package/src/commands/context.ts +3 -176
  338. package/src/commands/decision.ts +41 -7
  339. package/src/commands/deinit.ts +16 -16
  340. package/src/commands/doctor.ts +28 -28
  341. package/src/commands/{supervisor.ts → governor.ts} +184 -154
  342. package/src/commands/grep.ts +19 -2
  343. package/src/commands/init.ts +50 -34
  344. package/src/commands/{scratch.ts → journal.ts} +60 -60
  345. package/src/commands/policy.ts +1 -1
  346. package/src/commands/presence.ts +2 -2
  347. package/src/commands/sync.ts +3 -3
  348. package/src/commands/tunnel.ts +256 -38
  349. package/src/commands/web-fetch.ts +1 -1
  350. package/src/commands/web.ts +56 -1
  351. package/src/commands/work.ts +50 -35
  352. package/src/commands/workflow.ts +43 -34
  353. package/src/core/{harnesses → adapters}/attest-projection.ts +2 -2
  354. package/src/core/{harnesses → adapters}/attest.ts +27 -27
  355. package/src/core/{harnesses → adapters}/attestation.ts +41 -41
  356. package/src/core/{harnesses → adapters}/bench.ts +34 -43
  357. package/src/core/adapters/index.ts +56 -0
  358. package/src/core/{harnesses → adapters}/profiles.ts +16 -16
  359. package/src/core/{harnesses → adapters}/registry.ts +23 -23
  360. package/src/core/{harnesses → adapters}/types.ts +23 -23
  361. package/src/core/agents/canonical-emit.ts +16 -43
  362. package/src/core/agents/cli-emit.ts +1 -1
  363. package/src/core/agents/cli.ts +30 -28
  364. package/src/core/agents/codex-replay.ts +6 -6
  365. package/src/core/agents/coord-bin.ts +92 -0
  366. package/src/core/agents/coord-client.ts +302 -78
  367. package/src/core/agents/events/consume.ts +1 -1
  368. package/src/core/agents/events/emit.ts +7 -6
  369. package/src/core/agents/paths.ts +7 -11
  370. package/src/core/agents/render/prompt-context.ts +107 -31
  371. package/src/core/agents/render/session-context.ts +6 -6
  372. package/src/core/agents/rules/claim-conflict.ts +4 -7
  373. package/src/core/agents/rules/commit-conflict.ts +103 -22
  374. package/src/core/agents/rules/stop-hook.ts +33 -17
  375. package/src/core/agents/rules/verdict.ts +13 -0
  376. package/src/core/agents/session-events.ts +4 -4
  377. package/src/core/agents/state/council.ts +1 -1
  378. package/src/core/agents/state/heartbeat-projector.ts +16 -12
  379. package/src/core/agents/state/heartbeat-writer.ts +12 -12
  380. package/src/core/agents/state/{scratch.ts → journal.ts} +12 -12
  381. package/src/core/agents/state/pidmap.ts +130 -15
  382. package/src/core/agents/state/proc-start.ts +208 -0
  383. package/src/core/agents/state/shell-mutation.ts +1 -1
  384. package/src/core/agents/state/stale-sweep.ts +7 -7
  385. package/src/core/artifacts/index.ts +557 -0
  386. package/src/core/config.ts +30 -2
  387. package/src/core/context/index.ts +15 -15
  388. package/src/core/governor/adapter-spread.ts +82 -0
  389. package/src/core/governor/index.ts +91 -0
  390. package/src/core/governor/plan-api.ts +115 -0
  391. package/src/core/{supervisor → governor}/plan-read.ts +112 -97
  392. package/src/core/{supervisor → governor}/plan-types.ts +59 -56
  393. package/src/core/{supervisor → governor}/planning.ts +223 -192
  394. package/src/core/governor/read.ts +59 -0
  395. package/src/core/{supervisor → governor}/runner.ts +39 -39
  396. package/src/core/{supervisor → governor}/service-read.ts +22 -22
  397. package/src/core/{supervisor → governor}/service.ts +117 -119
  398. package/src/core/{supervisor → governor}/state.ts +325 -167
  399. package/src/core/hooks/adapter/detect.ts +30 -0
  400. package/src/core/hooks/{harness → adapter}/events.ts +16 -14
  401. package/src/core/hooks/{harness → adapter}/output.ts +31 -23
  402. package/src/core/hooks/{harness → adapter}/parse.ts +5 -5
  403. package/src/core/hooks/{harness → adapter}/wiring.ts +21 -21
  404. package/src/core/hooks/cli.ts +197 -173
  405. package/src/core/hooks/effects/image-capture.ts +6 -6
  406. package/src/core/hooks/effects/index.ts +19 -19
  407. package/src/core/hooks/events/emit.ts +3 -3
  408. package/src/core/hooks/events/rotate.ts +1 -1
  409. package/src/core/hooks/events/schema.ts +15 -7
  410. package/src/core/hooks/guard-path.ts +2 -2
  411. package/src/core/hooks/index.ts +1 -1
  412. package/src/core/hooks/resolve/anchor.ts +63 -8
  413. package/src/core/hooks/resolve/coord-root.ts +18 -40
  414. package/src/core/hooks/resolve/intent.ts +1 -1
  415. package/src/core/hooks/resolve/owner.ts +11 -5
  416. package/src/core/{scratch → journal}/index.ts +53 -53
  417. package/src/core/policy/evaluate.ts +8 -8
  418. package/src/core/policy/types.ts +3 -3
  419. package/src/core/work/state.ts +65 -23
  420. package/src/core/workflow/adapters.ts +33 -0
  421. package/src/core/workflow/approvals.ts +7 -7
  422. package/src/core/workflow/billing.ts +12 -12
  423. package/src/core/workflow/child-env.ts +13 -4
  424. package/src/core/workflow/engine.ts +155 -90
  425. package/src/core/workflow/evidence-preflight.ts +165 -0
  426. package/src/core/workflow/index.ts +3 -3
  427. package/src/core/workflow/proof.ts +60 -50
  428. package/src/core/workflow/run-state.ts +7 -7
  429. package/src/core/workflow/sandbox-projection.ts +16 -16
  430. package/src/core/workflow/spawn-claude.ts +13 -10
  431. package/src/core/workflow/spawn-codex.ts +13 -10
  432. package/src/core/workflow/spawn-cursor.ts +13 -10
  433. package/src/core/workflow/spawn-failure.ts +1 -1
  434. package/src/core/workflow/specialists.ts +2 -2
  435. package/src/core/workflow/{journal.ts → transcript.ts} +16 -16
  436. package/src/core/workflow/types.ts +108 -51
  437. package/src/core/workflow/validate.ts +1 -1
  438. package/src/core/workflow/workspaces/cancellation.ts +2 -2
  439. package/src/core/workflow/workspaces/cleanup.ts +2 -2
  440. package/src/core/workflow/workspaces/execution.ts +6 -6
  441. package/src/core/workflow/workspaces/inspect.ts +14 -11
  442. package/src/core/workflow/workspaces/integration.ts +18 -14
  443. package/src/core/workflow/workspaces/lifecycle.ts +10 -10
  444. package/src/core/workflow/workspaces/local-git.ts +47 -5
  445. package/src/core/workflow/workspaces/recovery.ts +3 -3
  446. package/src/core/workflow/workspaces/state.ts +4 -3
  447. package/src/core/workflow/workspaces/types.ts +1 -1
  448. package/src/lib/browser/asserts.ts +177 -0
  449. package/src/lib/browser/client.ts +189 -14
  450. package/src/lib/browser/content-checks.ts +571 -0
  451. package/src/lib/browser/critique.ts +231 -0
  452. package/src/lib/browser/geometry.ts +297 -1
  453. package/src/lib/browser/index.ts +34 -0
  454. package/src/lib/claude-desktop.ts +4 -1
  455. package/src/lib/context/index.ts +11 -1
  456. package/src/lib/council/index.ts +9 -9
  457. package/src/lib/identities/assume.ts +7 -7
  458. package/src/lib/instructions/apply.ts +87 -25
  459. package/src/lib/instructions/host-addendum.ts +126 -0
  460. package/src/lib/instructions/templates.ts +44 -15
  461. package/src/lib/machine.ts +2 -2
  462. package/dist/commands/harness.d.ts +0 -12
  463. package/dist/commands/harness.d.ts.map +0 -1
  464. package/dist/commands/scratch.d.ts +0 -4
  465. package/dist/commands/scratch.d.ts.map +0 -1
  466. package/dist/commands/session.d.ts.map +0 -1
  467. package/dist/commands/session.js +0 -162
  468. package/dist/commands/supervisor.d.ts +0 -4
  469. package/dist/commands/supervisor.d.ts.map +0 -1
  470. package/dist/core/harnesses/attest-projection.d.ts.map +0 -1
  471. package/dist/core/harnesses/attest.d.ts.map +0 -1
  472. package/dist/core/harnesses/attestation.d.ts.map +0 -1
  473. package/dist/core/harnesses/bench.d.ts.map +0 -1
  474. package/dist/core/harnesses/index.d.ts +0 -13
  475. package/dist/core/harnesses/index.d.ts.map +0 -1
  476. package/dist/core/harnesses/index.js +0 -6
  477. package/dist/core/harnesses/profiles.d.ts.map +0 -1
  478. package/dist/core/harnesses/registry.d.ts +0 -15
  479. package/dist/core/harnesses/registry.d.ts.map +0 -1
  480. package/dist/core/harnesses/types.d.ts.map +0 -1
  481. package/dist/core/hooks/harness/detect.d.ts +0 -9
  482. package/dist/core/hooks/harness/events.d.ts.map +0 -1
  483. package/dist/core/hooks/harness/output.d.ts.map +0 -1
  484. package/dist/core/supervisor/index.d.ts +0 -7
  485. package/dist/core/supervisor/index.d.ts.map +0 -1
  486. package/dist/core/supervisor/index.js +0 -6
  487. package/dist/core/supervisor/plan-api.d.ts +0 -23
  488. package/dist/core/supervisor/plan-api.d.ts.map +0 -1
  489. package/dist/core/supervisor/plan-api.js +0 -50
  490. package/dist/core/supervisor/plan-read.d.ts +0 -5
  491. package/dist/core/supervisor/plan-read.d.ts.map +0 -1
  492. package/dist/core/supervisor/plan-types.d.ts.map +0 -1
  493. package/dist/core/supervisor/planning.d.ts +0 -33
  494. package/dist/core/supervisor/planning.d.ts.map +0 -1
  495. package/dist/core/supervisor/read.d.ts +0 -6
  496. package/dist/core/supervisor/read.d.ts.map +0 -1
  497. package/dist/core/supervisor/read.js +0 -4
  498. package/dist/core/supervisor/runner.d.ts +0 -37
  499. package/dist/core/supervisor/runner.d.ts.map +0 -1
  500. package/dist/core/supervisor/service-read.d.ts +0 -6
  501. package/dist/core/supervisor/service-read.d.ts.map +0 -1
  502. package/dist/core/supervisor/service.d.ts +0 -114
  503. package/dist/core/supervisor/service.d.ts.map +0 -1
  504. package/dist/core/supervisor/state.d.ts +0 -95
  505. package/dist/core/supervisor/state.d.ts.map +0 -1
  506. package/dist/core/workflow/harnesses.d.ts +0 -17
  507. package/dist/core/workflow/harnesses.d.ts.map +0 -1
  508. package/dist/core/workflow/harnesses.js +0 -21
  509. package/dist/core/workflow/journal.d.ts.map +0 -1
  510. package/src/commands/session.ts +0 -187
  511. package/src/core/harnesses/index.ts +0 -56
  512. package/src/core/hooks/harness/detect.ts +0 -30
  513. package/src/core/supervisor/index.ts +0 -89
  514. package/src/core/supervisor/plan-api.ts +0 -73
  515. package/src/core/supervisor/read.ts +0 -59
  516. package/src/core/workflow/harnesses.ts +0 -33
  517. /package/dist/core/{harnesses → adapters}/attest-projection.js +0 -0
@@ -3,8 +3,8 @@
3
3
  * alongside the legacy stream.
4
4
  *
5
5
  * Flow:
6
- * 1. Parse argv → event-name + harness.
7
- * 2. Read stdin → harness payload (JSON or empty).
6
+ * 1. Parse argv → event-name + adapter.
7
+ * 2. Read stdin → adapter payload (JSON or empty).
8
8
  * 3. Find coord root (walk up for .harnery/).
9
9
  * 4. Resolve instance_id (env → payload → pid-map walk).
10
10
  * 5. Map event-name → canonical event_type.
@@ -15,7 +15,7 @@
15
15
  * Phase 2 ship criterion: confirms parser correctness across thousands of
16
16
  * real events without affecting behavior. Always exits 0. Failures land in
17
17
  * `.harnery/debug/agent-hook.errors.ndjson` for audit but never break the
18
- * harness flow.
18
+ * adapter flow.
19
19
  */
20
20
 
21
21
  import { spawnSync } from "node:child_process";
@@ -23,9 +23,11 @@ import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
23
23
  import { dirname, join } from "node:path";
24
24
  import { coordEnv } from "../../lib/env.ts";
25
25
  import { replayCodexJsonl } from "../agents/codex-replay.ts";
26
+ import { coordBinPath } from "../agents/coord-bin.ts";
26
27
  import { consumeSince, writeCursor } from "../agents/events/consume.ts";
27
28
  import { evaluateStopHook } from "../agents/rules/stop-hook.ts";
28
29
  import { projectHeartbeats } from "../agents/state/heartbeat-projector.ts";
30
+ import { writePidmapRow } from "../agents/state/pidmap.ts";
29
31
  import { shellMutationPaths } from "../agents/state/shell-mutation.ts";
30
32
  import {
31
33
  checkpointContext,
@@ -38,32 +40,32 @@ import {
38
40
  recordContextSample,
39
41
  } from "../context/index.ts";
40
42
  import { ensureRelayDaemon, fetchPresence, publishPresence } from "../presence/index.ts";
43
+ import { detectAdapter } from "./adapter/detect.ts";
44
+ import {
45
+ extractBashCommand,
46
+ extractToolDescription,
47
+ type NormalizedEventType,
48
+ normalizeEventName,
49
+ type ParsedPayload,
50
+ parsePayload,
51
+ } from "./adapter/parse.ts";
41
52
  import {
42
53
  captureImages,
43
54
  detectPresence,
44
55
  imageJanitor,
56
+ journalArchive,
57
+ journalJanitor,
58
+ journalRecoveryCue,
45
59
  playSound,
46
60
  resetSoundCounters,
47
61
  runSessionSyncExtension,
48
62
  runTurnSummary,
49
- scratchArchive,
50
- scratchJanitor,
51
- scratchRecoveryCue,
52
63
  soundForEvent,
53
64
  } from "./effects/index.ts";
54
65
  import { emit } from "./events/emit.ts";
55
- import type { Harness } from "./events/schema.ts";
66
+ import type { Adapter } from "./events/schema.ts";
56
67
  import { canonicalize } from "./guard-path.ts";
57
- import { detectHarness } from "./harness/detect.ts";
58
- import {
59
- extractBashCommand,
60
- extractToolDescription,
61
- type NormalizedEventType,
62
- normalizeEventName,
63
- type ParsedPayload,
64
- parsePayload,
65
- } from "./harness/parse.ts";
66
- import { parsePsChainLine, selectAnchorPid } from "./resolve/anchor.ts";
68
+ import { adapterPidFromEnv, parsePsChainLine, selectAnchorPid } from "./resolve/anchor.ts";
67
69
  import { findCoordRoot } from "./resolve/coord-root.ts";
68
70
  import { extractIntentComment, resolveIntent } from "./resolve/intent.ts";
69
71
  import { resolveOwner } from "./resolve/owner.ts";
@@ -78,11 +80,11 @@ function parseArgv(argv: string[]): Argv {
78
80
  const out: Argv = { eventName: null, extra: [] };
79
81
  for (let i = 0; i < argv.length; i++) {
80
82
  const arg = argv[i]!;
81
- if (arg === "--harness") {
82
- i++; // detectHarness will re-parse; just consume the value here.
83
+ if (arg === "--adapter") {
84
+ i++; // detectAdapter will re-parse; just consume the value here.
83
85
  continue;
84
86
  }
85
- if (arg.startsWith("--harness=")) continue;
87
+ if (arg.startsWith("--adapter=")) continue;
86
88
  if (!out.eventName && !arg.startsWith("--")) {
87
89
  out.eventName = arg;
88
90
  } else {
@@ -108,7 +110,7 @@ async function readStdin(): Promise<string> {
108
110
  /**
109
111
  * Env for child agent-coord spawns, with the coord root pinned. The hook
110
112
  * process may be running with the session shell's cwd (inside a submodule or
111
- * scratch dir), and agent-coord resolves its root from cwd unless overridden —
113
+ * journal dir), and agent-coord resolves its root from cwd unless overridden —
112
114
  * without the pin a child could write state to a different .harnery than the
113
115
  * one this hook resolved.
114
116
  */
@@ -149,7 +151,7 @@ function logError(coordRoot: string | null, err: unknown, context: Record<string
149
151
  /**
150
152
  * Spawn `agent-coord assign-name <owner> <kind>` to mint or recover the
151
153
  * hurricane-style name for this owner. Returns null on any failure so
152
- * session.start emission never breaks the harness flow.
154
+ * session.start emission never breaks the adapter flow.
153
155
  *
154
156
  * Lives at agent-hooks side (not agent-coord) to keep emitter/consumer
155
157
  * separation: we spawn rather than import.
@@ -159,7 +161,7 @@ function assignNameViaAgentCoord(
159
161
  instanceId: string,
160
162
  kind: "session" | "subagent" | "transient",
161
163
  ): { name: string; kind: string } | null {
162
- const binary = join(coordRoot, "harnery", "bin", "agent-coord");
164
+ const binary = coordBinPath("agent-coord", coordRoot) ?? "";
163
165
  if (!existsSync(binary)) return null;
164
166
  try {
165
167
  const result = spawnSync(binary, ["assign-name", instanceId, kind], {
@@ -182,9 +184,15 @@ function assignNameViaAgentCoord(
182
184
  }
183
185
 
184
186
  /**
185
- * Direct (in-process) pidmap write, avoids the spawn overhead of going via
186
- * the agent-coord CLI for every session.start / subagent.start. Pid-map
187
- * rows are essential for `harn agents whoami` ppid resolution.
187
+ * Direct (in-process) pidmap write, avoiding the spawn overhead of going via
188
+ * the agent-coord CLI for every session.start / subagent.start. Pid-map rows
189
+ * are essential for `harn agents whoami` ppid resolution.
190
+ *
191
+ * This used to inline its own copy of the write to keep this module's
192
+ * dependencies narrow, which quietly mattered: the shared writer is where row
193
+ * hygiene lives, so the duplicate meant the only hot write path in the system
194
+ * never swept dead rows, and the map grew unbounded. It calls the shared writer
195
+ * now, and this module already imports from that directory anyway.
188
196
  */
189
197
  function writePidmapViaAgentCoord(
190
198
  coordRoot: string,
@@ -193,26 +201,9 @@ function writePidmapViaAgentCoord(
193
201
  platform: string,
194
202
  ): void {
195
203
  try {
196
- // Inline write: same atomic temp+rename pattern as
197
- // agent-coord/src/state/pidmap.ts but skips importing across module
198
- // boundaries to keep agent-hooks's deps explicit.
199
- const dir = join(coordRoot, ".harnery", "pid-map");
200
- const path = join(dir, String(pid));
201
- const row = `${instanceId}\t${platform}`;
202
- if (existsSync(path)) {
203
- try {
204
- const current = require("node:fs").readFileSync(path, "utf8");
205
- if (current === row) return;
206
- } catch {
207
- /* fall through */
208
- }
209
- }
210
- mkdirSync(dir, { recursive: true });
211
- const tmp = `${path}.tmp.${process.pid}`;
212
- require("node:fs").writeFileSync(tmp, row, "utf8");
213
- require("node:fs").renameSync(tmp, path);
204
+ writePidmapRow(coordRoot, pid, instanceId, platform);
214
205
  } catch {
215
- /* never break the harness flow */
206
+ /* never break the adapter flow */
216
207
  }
217
208
  }
218
209
 
@@ -234,7 +225,7 @@ interface BuildContext {
234
225
  coordRoot: string;
235
226
  payload: ParsedPayload | null;
236
227
  raw: string;
237
- harness: Harness;
228
+ adapter: Adapter;
238
229
  instanceId: string;
239
230
  }
240
231
 
@@ -245,24 +236,24 @@ function buildEventData(
245
236
  const p = ctx.payload;
246
237
  switch (eventType) {
247
238
  case "session.start": {
248
- const harnessPlatform =
249
- ctx.harness === "claude-code"
239
+ const adapterPlatform =
240
+ ctx.adapter === "claude-code"
250
241
  ? "claude_code"
251
- : ctx.harness === "cursor"
242
+ : ctx.adapter === "cursor"
252
243
  ? "cursor"
253
244
  : "codex";
254
245
  // Assign (or recover) name + kind via agent-coord. Idempotent: resume
255
246
  // returns the original name; new owner consumes a counter slot.
256
247
  const assigned = assignNameViaAgentCoord(ctx.coordRoot, ctx.instanceId, "session");
257
- // Write the harness pid-map row so `harn agents whoami` ppid-walks find
248
+ // Write the adapter pid-map row so `harn agents whoami` ppid-walks find
258
249
  // this owner. Prefer the payload pid (the actual claude binary), then the
259
250
  // anchor walk (the `node` ancestor for Cursor, which has no payload pid),
260
251
  // then our own process.ppid. Without the anchor, Cursor anchored on the
261
252
  // ephemeral hook bash parent, a PID that dies before the agent's next
262
253
  // shell tool call, so the ppid walk found nothing (no_pidmap_entry).
263
- const harnessPid = p?.pid ?? findHarnessAnchorPid(ctx.harness) ?? process.ppid;
264
- if (harnessPid) {
265
- writePidmapViaAgentCoord(ctx.coordRoot, harnessPid, ctx.instanceId, harnessPlatform);
254
+ const adapterPid = p?.pid ?? findAdapterAnchorPid(ctx.adapter) ?? process.ppid;
255
+ if (adapterPid) {
256
+ writePidmapViaAgentCoord(ctx.coordRoot, adapterPid, ctx.instanceId, adapterPlatform);
266
257
  }
267
258
  return {
268
259
  started_at: new Date().toISOString(),
@@ -271,17 +262,25 @@ function buildEventData(
271
262
  // supply it). Fall back to the transcript, populated on `resume`, and
272
263
  // backfilled later by `turn.stop` for a fresh `startup` session.
273
264
  model: p?.model ?? scanTranscriptModel(p?.transcript_path),
274
- pid: harnessPid,
265
+ pid: adapterPid,
275
266
  source: p?.source,
276
- platform: harnessPlatform,
267
+ platform: adapterPlatform,
277
268
  name: assigned?.name,
278
269
  kind: "session",
279
270
  agent_id: ctx.instanceId,
280
271
  // Workflow-child linkage: `workflow run` children carry the run id in
281
272
  // env (spawn adapters set it via buildChildEnv), so their sessions and
282
- // heartbeats join back to the run journal + /workflows web view.
273
+ // heartbeats join back to the run transcript + /workflows web view.
283
274
  ...(coordEnv("WORKFLOW_CHILD") === "1" && coordEnv("WORKFLOW_RUN_ID")
284
- ? { workflow_run_id: coordEnv("WORKFLOW_RUN_ID") }
275
+ ? {
276
+ workflow_run_id: coordEnv("WORKFLOW_RUN_ID"),
277
+ // Which agent row of that run this session is. The orchestrator
278
+ // stamps it on the way in, because the adapter does not report a
279
+ // session id until the agent has already finished.
280
+ ...(coordEnv("WORKFLOW_AGENT_ID")
281
+ ? { workflow_agent_id: coordEnv("WORKFLOW_AGENT_ID") }
282
+ : {}),
283
+ }
285
284
  : {}),
286
285
  };
287
286
  }
@@ -300,7 +299,7 @@ function buildEventData(
300
299
 
301
300
  case "turn.stop": {
302
301
  return {
303
- // Backfill the model for harnesses that omit it at session.start
302
+ // Backfill the model for adapters that omit it at session.start
304
303
  // (Claude Code). The transcript is populated with assistant turns by
305
304
  // Stop-hook time, so this resolves even for fresh `startup` sessions.
306
305
  model: p?.model ?? scanTranscriptModel(p?.transcript_path),
@@ -442,14 +441,14 @@ function numberField(value: unknown): number | undefined {
442
441
 
443
442
  async function main(): Promise<number> {
444
443
  const { eventName, extra } = parseArgv(process.argv.slice(2));
445
- const harness = detectHarness(process.argv.slice(2));
444
+ const adapter = detectAdapter(process.argv.slice(2));
446
445
  const raw = await readStdin();
447
446
 
448
447
  // Kill-switch-INDEPENDENT effects: notification sounds fire BEFORE the
449
448
  // HARNERY_AGENT_COORD_OFF gate so audible feedback survives incident-triage
450
449
  // bypass: sound playback happens before the kill-switch bailout.
451
450
  // Claude-Code-only; stop-failure → error, sub-agent-start → subagent-start.
452
- if (harness === "claude-code" && eventName) {
451
+ if (adapter === "claude-code" && eventName) {
453
452
  const s = soundForEvent(eventName);
454
453
  if (s) {
455
454
  const repoRoot = findCoordRoot(process.cwd());
@@ -481,7 +480,7 @@ async function main(): Promise<number> {
481
480
  const debugBase = {
482
481
  ts: new Date().toISOString(),
483
482
  event_name: eventName,
484
- harness,
483
+ adapter,
485
484
  extra_argv: extra,
486
485
  payload_bytes: raw.length,
487
486
  cwd: process.cwd(),
@@ -489,8 +488,8 @@ async function main(): Promise<number> {
489
488
  ppid: process.ppid,
490
489
  };
491
490
 
492
- if (!eventName || !harness) {
493
- appendDebug(coordRoot, { ...debugBase, skipped: "missing-event-or-harness" });
491
+ if (!eventName || !adapter) {
492
+ appendDebug(coordRoot, { ...debugBase, skipped: "missing-event-or-adapter" });
494
493
  return 0;
495
494
  }
496
495
 
@@ -500,7 +499,7 @@ async function main(): Promise<number> {
500
499
  return 0;
501
500
  }
502
501
 
503
- const payload = parsePayload(raw, harness);
502
+ const payload = parsePayload(raw, adapter);
504
503
  const owner = resolveOwner({ payload: payload?.raw ?? null, coordRoot });
505
504
  if (!owner) {
506
505
  appendDebug(coordRoot, {
@@ -517,7 +516,7 @@ async function main(): Promise<number> {
517
516
  coordRoot,
518
517
  payload,
519
518
  raw,
520
- harness,
519
+ adapter,
521
520
  instanceId: owner.instance_id,
522
521
  });
523
522
 
@@ -528,7 +527,7 @@ async function main(): Promise<number> {
528
527
  parent_session_id: payload?.parent_session_id,
529
528
  turn_id: payload?.turn_id,
530
529
  parent_turn_id: payload?.parent_turn_id,
531
- harness,
530
+ adapter,
532
531
  data,
533
532
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
534
533
  } as Parameters<typeof emit>[1]);
@@ -541,13 +540,13 @@ async function main(): Promise<number> {
541
540
  });
542
541
 
543
542
  // Context telemetry is opportunistic and truthful: only persist a sample
544
- // when the harness payload actually exposes usage/window data. Identical
543
+ // when the adapter payload actually exposes usage/window data. Identical
545
544
  // measurements are de-duplicated before they reach the canonical stream.
546
545
  if (payload?.raw) {
547
546
  try {
548
547
  const sample = extractContextSample(payload.raw, {
549
548
  sessionId,
550
- harness,
549
+ adapter,
551
550
  model: payload.model,
552
551
  source: "hook",
553
552
  confidence: "reported",
@@ -559,7 +558,7 @@ async function main(): Promise<number> {
559
558
  event_type: "context.sampled",
560
559
  instance_id: owner.instance_id,
561
560
  session_id: sessionId,
562
- harness,
561
+ adapter,
563
562
  data: {
564
563
  model: sample.model,
565
564
  used_tokens: sample.used_tokens,
@@ -578,13 +577,13 @@ async function main(): Promise<number> {
578
577
 
579
578
  // A native pre-compaction signal is the safest available point to capture
580
579
  // external work state. The operation is idempotent until recovery, so a
581
- // harness retry cannot create a storm of near-identical capsules.
580
+ // adapter retry cannot create a storm of near-identical capsules.
582
581
  if (norm.event_type === "context.compaction.started") {
583
582
  try {
584
583
  const checkpoint = checkpointContext(coordRoot, {
585
584
  sessionId,
586
585
  instanceId: owner.instance_id,
587
- harness,
586
+ adapter,
588
587
  cwd: payload?.cwd ?? process.cwd(),
589
588
  reason: "pre_compact",
590
589
  model: payload?.model,
@@ -593,7 +592,7 @@ async function main(): Promise<number> {
593
592
  event_type: "context.checkpoint.created",
594
593
  instance_id: owner.instance_id,
595
594
  session_id: sessionId,
596
- harness,
595
+ adapter,
597
596
  data: {
598
597
  capsule_id: checkpoint.capsule.capsule_id,
599
598
  generation: checkpoint.capsule.generation,
@@ -619,17 +618,17 @@ async function main(): Promise<number> {
619
618
  }
620
619
 
621
620
  // Phase 8: SessionStart post-emit: project the event so the heartbeat
622
- // lands synchronously, run stale-sweep, and emit the harness-shaped
621
+ // lands synchronously, run stale-sweep, and emit the adapter-shaped
623
622
  // systemMessage JSON (peer table + wiring check + council invites).
624
- // Harness-agnostic since v0.5.0; replaces the previous bash UX layer
625
- // and the equivalent per-harness bash session_start handlers.
623
+ // Adapter-agnostic since v0.5.0; replaces the previous bash UX layer
624
+ // and the equivalent per-adapter bash session_start handlers.
626
625
  if (norm.event_type === "session.start") {
627
- // Effect (claude-code): prune stale scratch archives + sweep orphans.
626
+ // Effect (claude-code): prune stale journal archives + sweep orphans.
628
627
  // The recovery-cue is merged into the
629
628
  // session-start additionalContext inside emitSessionStartSystemMessage.
630
- if (harness === "claude-code") scratchJanitor(coordRoot);
631
- // Image-feed retention sweep (size + age cap on .harnery/images/). Harness-
632
- // agnostic, cheap (one readdir), fail-soft. Paired with scratchJanitor as a
629
+ if (adapter === "claude-code") journalJanitor(coordRoot);
630
+ // Image-feed retention sweep (size + age cap on .harnery/images/). Adapter-
631
+ // agnostic, cheap (one readdir), fail-soft. Paired with journalJanitor as a
633
632
  // session-start "tidy the coord layer" step.
634
633
  try {
635
634
  imageJanitor(coordRoot);
@@ -643,7 +642,7 @@ async function main(): Promise<number> {
643
642
  event_type: "context.compaction.completed",
644
643
  instance_id: owner.instance_id,
645
644
  session_id: sessionId,
646
- harness,
645
+ adapter,
647
646
  data: { trigger: "auto" },
648
647
  });
649
648
  markContextCompactionCompleted(coordRoot, {
@@ -665,7 +664,7 @@ async function main(): Promise<number> {
665
664
  owner.instance_id,
666
665
  sessionId,
667
666
  data,
668
- harness,
667
+ adapter,
669
668
  recovery?.briefing ?? "",
670
669
  );
671
670
  if (injected && recovery) {
@@ -673,7 +672,7 @@ async function main(): Promise<number> {
673
672
  coordRoot,
674
673
  owner.instance_id,
675
674
  sessionId,
676
- harness,
675
+ adapter,
677
676
  recovery,
678
677
  "SessionStart",
679
678
  );
@@ -693,7 +692,7 @@ async function main(): Promise<number> {
693
692
  }
694
693
  }
695
694
 
696
- // Phase 8: SessionEnd cleanup: delete heartbeat + pid-map rows. Harness-
695
+ // Phase 8: SessionEnd cleanup: delete heartbeat + pid-map rows. Adapter-
697
696
  // agnostic since v0.5.0.
698
697
  if (norm.event_type === "session.end") {
699
698
  try {
@@ -701,10 +700,10 @@ async function main(): Promise<number> {
701
700
  } catch (err) {
702
701
  logError(coordRoot, err, { phase: "session-end-cleanup" });
703
702
  }
704
- // Effects (claude-code): archive the ending agent's scratchpad + force a
703
+ // Effects (claude-code): archive the ending agent's journal + force a
705
704
  // session-telemetry sync (via HARNERY_CLAUDE_SESSIONS_FORCE=1).
706
- if (harness === "claude-code") {
707
- scratchArchive(coordRoot, owner.instance_id);
705
+ if (adapter === "claude-code") {
706
+ journalArchive(coordRoot, owner.instance_id);
708
707
  runSessionSyncExtension(coordRoot, true);
709
708
  }
710
709
  // Presence: publish the post-cleanup state so peers see this session gone
@@ -721,7 +720,7 @@ async function main(): Promise<number> {
721
720
  // subagent (claude-code + cursor; codex doesn't fan out subagents today).
722
721
  if (norm.event_type === "subagent.start") {
723
722
  try {
724
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
723
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
725
724
  if (existsSync(agentCoordBin)) {
726
725
  spawnSync(agentCoordBin, ["project"], {
727
726
  encoding: "utf8",
@@ -732,14 +731,14 @@ async function main(): Promise<number> {
732
731
  agentCoordBin,
733
732
  [
734
733
  "log",
735
- `SUBAGENT_START agent_type=${(data.agent_type as string) ?? "unknown"} agent_id=${owner.instance_id.slice(0, 8)} platform=${harnessPlatform(harness)}`,
734
+ `SUBAGENT_START agent_type=${(data.agent_type as string) ?? "unknown"} agent_id=${owner.instance_id.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
736
735
  "--instance",
737
736
  owner.instance_id,
738
737
  ],
739
738
  { encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) },
740
739
  );
741
740
  }
742
- emitSubagentStartContext(coordRoot, owner.instance_id, sessionId, data, harness);
741
+ emitSubagentStartContext(coordRoot, owner.instance_id, sessionId, data, adapter);
743
742
  } catch (err) {
744
743
  logError(coordRoot, err, { phase: "subagent-start-project" });
745
744
  }
@@ -749,13 +748,13 @@ async function main(): Promise<number> {
749
748
  if (norm.event_type === "subagent.stop") {
750
749
  try {
751
750
  cleanupSessionEnd(coordRoot, owner.instance_id, (data.reason as string) ?? "unknown");
752
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
751
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
753
752
  if (existsSync(agentCoordBin)) {
754
753
  spawnSync(
755
754
  agentCoordBin,
756
755
  [
757
756
  "log",
758
- `SUBAGENT_STOP agent_id=${owner.instance_id.slice(0, 8)} platform=${harnessPlatform(harness)}`,
757
+ `SUBAGENT_STOP agent_id=${owner.instance_id.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
759
758
  "--instance",
760
759
  owner.instance_id,
761
760
  ],
@@ -768,11 +767,11 @@ async function main(): Promise<number> {
768
767
  }
769
768
 
770
769
  // Phase 8: UserPromptSubmit: render dedup'd peer table + council pending
771
- // and emit the harness-shaped systemMessage JSON. Harness-agnostic since v0.5.0.
770
+ // and emit the adapter-shaped systemMessage JSON. Adapter-agnostic since v0.5.0.
772
771
  if (norm.event_type === "user_prompt.submit") {
773
772
  // Effects (claude-code): reset per-turn sound rate-limit counters + run
774
773
  // presence detection on the prompt.
775
- if (harness === "claude-code") {
774
+ if (adapter === "claude-code") {
776
775
  resetSoundCounters(sessionId);
777
776
  const prompt = (payload?.raw?.prompt as string | undefined) ?? "";
778
777
  if (prompt) detectPresence(prompt);
@@ -805,7 +804,7 @@ async function main(): Promise<number> {
805
804
  coordRoot,
806
805
  owner.instance_id,
807
806
  sessionId,
808
- harness,
807
+ adapter,
809
808
  recovery?.briefing ?? "",
810
809
  );
811
810
  if (injected && recovery) {
@@ -813,7 +812,7 @@ async function main(): Promise<number> {
813
812
  coordRoot,
814
813
  owner.instance_id,
815
814
  sessionId,
816
- harness,
815
+ adapter,
817
816
  recovery,
818
817
  "UserPromptSubmit",
819
818
  );
@@ -824,7 +823,7 @@ async function main(): Promise<number> {
824
823
  }
825
824
 
826
825
  // turn.stop: telemetry + turn-summary effects, then the stop verdict. The
827
- // verdict + codex-replay previously lived in the per-harness shell adapters;
826
+ // verdict + codex-replay previously lived in the per-adapter shell adapters;
828
827
  // agent-hook owns them now. Runs on the normal "stop" event only;
829
828
  // "stop-failure" (API error) gets no gate, matching the previous
830
829
  // stop vs stop-failure split.
@@ -833,7 +832,7 @@ async function main(): Promise<number> {
833
832
  // the status_checked / task_set / status_box_present evidence (codex
834
833
  // doesn't emit those live; this re-emits turn.stop after agent-hook's own,
835
834
  // so the verdict reads the replay's box signal as the latest).
836
- if (harness === "codex" && payload?.transcript_path && existsSync(payload.transcript_path)) {
835
+ if (adapter === "codex" && payload?.transcript_path && existsSync(payload.transcript_path)) {
837
836
  try {
838
837
  replayCodexJsonl({
839
838
  coordRoot,
@@ -849,7 +848,7 @@ async function main(): Promise<number> {
849
848
 
850
849
  // CC effects: rate-limited session-telemetry sync + turn-summary Haiku
851
850
  // auto-summary.
852
- if (harness === "claude-code") {
851
+ if (adapter === "claude-code") {
853
852
  runSessionSyncExtension(coordRoot, false);
854
853
  runTurnSummary(coordRoot, owner.instance_id, sessionId, payload?.transcript_path);
855
854
  }
@@ -857,7 +856,7 @@ async function main(): Promise<number> {
857
856
  // Master-state heartbeat projection. Drains events.ndjson since the last
858
857
  // cursor → per-owner heartbeats. Was a SECOND binary (`agent-coord project`)
859
858
  // pinned to Claude Code Stop only; folded in here so it (a) is one
860
- // entry per event like everything else and (b) fires on EVERY harness's stop,
859
+ // entry per event like everything else and (b) fires on EVERY adapter's stop,
861
860
  // not just CC. Runs unconditionally before the verdict's possible exit-2 return
862
861
  // (the events are real regardless of whether the agent gets nagged), and after
863
862
  // codex-replay above so codex's replayed events are included in the drain.
@@ -888,22 +887,22 @@ async function main(): Promise<number> {
888
887
  rule: "stop-hook",
889
888
  instance_id: owner.instance_id,
890
889
  session_id: sessionId,
891
- harness,
890
+ adapter,
892
891
  bypass: coordEnv("AGENT_COORD_BYPASS_STOP") === "1",
893
892
  workflow_child: coordEnv("WORKFLOW_CHILD") === "1",
894
893
  });
895
894
  if (!verdict.allow) {
896
- // Harness-aware enforcement channel: Claude Code / Codex honor exit-2 +
895
+ // Adapter-aware enforcement channel: Claude Code / Codex honor exit-2 +
897
896
  // stderr as a turn block; Cursor ignores exit codes (fail-open) and
898
897
  // re-prompts only via a `followup_message` it auto-submits. emitStopBlock
899
898
  // writes the right shape and returns the exit code to use.
900
- const { emitStopBlock } = await import("./harness/output.ts");
901
- return emitStopBlock(harness, verdict);
899
+ const { emitStopBlock } = await import("./adapter/output.ts");
900
+ return emitStopBlock(adapter, verdict);
902
901
  }
903
902
  }
904
903
 
905
904
  // Phase 7: PreToolUse: heartbeat + pid-map self-heal on every tool call.
906
- // Harness-agnostic: both writes have the same shape regardless of who fired.
905
+ // Adapter-agnostic: both writes have the same shape regardless of who fired.
907
906
  // Cursor/Codex bash dispatchers still fire their own G-guard logic, but the
908
907
  // heals here keep the agent-coord layer's view of liveness fresh.
909
908
  //
@@ -913,8 +912,8 @@ async function main(): Promise<number> {
913
912
  // call was restored here afterward.
914
913
  if (norm.event_type === "tool.pre_use") {
915
914
  try {
916
- healHeartbeatViaCli(coordRoot, owner.instance_id, sessionId, harness);
917
- refreshPidmap(coordRoot, owner.instance_id, harness, payload?.pid);
915
+ healHeartbeatViaCli(coordRoot, owner.instance_id, sessionId, adapter);
916
+ refreshPidmap(coordRoot, owner.instance_id, adapter, payload?.pid);
918
917
  } catch (err) {
919
918
  logError(coordRoot, err, { phase: "pre-tool-use-heal" });
920
919
  }
@@ -928,29 +927,29 @@ async function main(): Promise<number> {
928
927
  payload,
929
928
  instanceId: owner.instance_id,
930
929
  sessionId,
931
- harness,
930
+ adapter,
932
931
  });
933
932
  } catch (err) {
934
933
  logError(coordRoot, err, { phase: "pre-tool-use-image-capture" });
935
934
  }
936
935
 
937
- // G-guard for ALL harnesses. Claude Code previously ran this via a
936
+ // G-guard for ALL adapters. Claude Code previously ran this via a
938
937
  // pre-tool-use bash adapter (which called `agent-coord verdict --rule=claim`);
939
- // that adapter is now deleted, so agent-hook owns the deny for every harness.
940
- // emitDeny() inside emits the harness-shaped permission JSON (claude-code +
938
+ // that adapter is now deleted, so agent-hook owns the deny for every adapter.
939
+ // emitDeny() inside emits the adapter-shaped permission JSON (claude-code +
941
940
  // codex use hookSpecificOutput.permissionDecision; cursor uses .permission).
942
941
  // apply_patch (codex) parses paths from the patch body and runs verdict
943
942
  // per-path; Edit/Write/NotebookEdit resolve a single target. Non-write tools
944
943
  // (incl. Agent) yield no targets and pass through with no deny.
945
944
  try {
946
- await runPreToolUseGuard(coordRoot, owner.instance_id, sessionId, data, harness);
945
+ await runPreToolUseGuard(coordRoot, owner.instance_id, sessionId, data, adapter);
947
946
  } catch (err) {
948
947
  logError(coordRoot, err, { phase: "pre-tool-use-guard" });
949
948
  }
950
949
 
951
950
  // Shell-mutation warn (warn-only, never blocks). Was the cursor
952
951
  // beforeShellExecution + codex preToolUse-Bash shell-mutation-claim-log in
953
- // the per-harness shell adapters. Cursor sends the command at payload.command;
952
+ // the per-adapter shell adapters. Cursor sends the command at payload.command;
954
953
  // codex Bash at tool_input.command. Emits a decision.warn per candidate-mutated
955
954
  // path so a peer sees the write in events.ndjson. (CC never did this,
956
955
  // preserved; it emits with its own hooks-side emitter per the
@@ -958,7 +957,7 @@ async function main(): Promise<number> {
958
957
  const shellCmd =
959
958
  eventName === "before-shell-execution"
960
959
  ? ((payload?.raw.command as string | undefined) ?? "")
961
- : harness === "codex" && data.tool_name === "Bash"
960
+ : adapter === "codex" && data.tool_name === "Bash"
962
961
  ? (((payload?.raw.tool_input as Record<string, unknown> | undefined)?.command as
963
962
  | string
964
963
  | undefined) ?? "")
@@ -967,13 +966,13 @@ async function main(): Promise<number> {
967
966
  try {
968
967
  const paths = shellMutationPaths(shellCmd, coordRoot);
969
968
  const truncated = shellCmd.length > 80 ? shellCmd.slice(0, 80) : shellCmd;
970
- const platform = harnessPlatform(harness);
969
+ const platform = adapterPlatform(adapter);
971
970
  for (const p of paths) {
972
971
  emit(coordRoot, {
973
972
  event_type: "decision.warn",
974
973
  instance_id: owner.instance_id,
975
974
  session_id: sessionId,
976
- harness,
975
+ adapter,
977
976
  data: {
978
977
  rule: "shell_mutation_candidate",
979
978
  reason: `path=${p} cmd=${truncated} platform=${platform}`,
@@ -988,7 +987,7 @@ async function main(): Promise<number> {
988
987
  }
989
988
 
990
989
  // Phase 7: PostToolUse: stamp last_tool + last_tool_target on heartbeat.
991
- // Harness-agnostic for the same reason as tool.pre_use above.
990
+ // Adapter-agnostic for the same reason as tool.pre_use above.
992
991
  if (norm.event_type === "tool.post_use") {
993
992
  try {
994
993
  stampToolActivity(coordRoot, owner.instance_id, data);
@@ -1006,7 +1005,7 @@ async function main(): Promise<number> {
1006
1005
  payload,
1007
1006
  instanceId: owner.instance_id,
1008
1007
  sessionId,
1009
- harness,
1008
+ adapter,
1010
1009
  });
1011
1010
  } catch (err) {
1012
1011
  logError(coordRoot, err, { phase: "post-tool-use-image-capture" });
@@ -1014,7 +1013,7 @@ async function main(): Promise<number> {
1014
1013
  }
1015
1014
 
1016
1015
  // Phase 7: PostToolUseFailure: release claim on failed Edit (the file
1017
- // never landed; the claim is stale). Harness-agnostic.
1016
+ // never landed; the claim is stale). Adapter-agnostic.
1018
1017
  if (norm.event_type === "tool.post_use_failure") {
1019
1018
  try {
1020
1019
  releaseClaimOnFailure(coordRoot, owner.instance_id, data, payload?.raw);
@@ -1031,7 +1030,7 @@ async function runPreToolUseGuard(
1031
1030
  instanceId: string,
1032
1031
  sessionId: string,
1033
1032
  data: Record<string, unknown>,
1034
- harness: Harness,
1033
+ adapter: Adapter,
1035
1034
  ): Promise<void> {
1036
1035
  const toolName = (data.tool_name as string | undefined) ?? "";
1037
1036
  const targets = collectGuardTargets(toolName, data)
@@ -1039,7 +1038,7 @@ async function runPreToolUseGuard(
1039
1038
  .filter((p): p is string => p !== null);
1040
1039
  if (targets.length === 0) return;
1041
1040
 
1042
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1041
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1043
1042
  if (!existsSync(agentCoordBin)) return;
1044
1043
 
1045
1044
  // For apply_patch (multi-file), collect siblings so the deny reason names
@@ -1075,8 +1074,8 @@ async function runPreToolUseGuard(
1075
1074
  reason += ` The patch also touched: ${siblings}: pick a different file or wait.`;
1076
1075
  }
1077
1076
  }
1078
- const { emitDeny } = await import("./harness/output.ts");
1079
- emitDeny(harness, reason);
1077
+ const { emitDeny } = await import("./adapter/output.ts");
1078
+ emitDeny(adapter, reason);
1080
1079
  return;
1081
1080
  }
1082
1081
  }
@@ -1142,15 +1141,15 @@ function healHeartbeatViaCli(
1142
1141
  coordRoot: string,
1143
1142
  instanceId: string,
1144
1143
  sessionId: string,
1145
- harness: string,
1144
+ adapter: string,
1146
1145
  ): void {
1147
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1146
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1148
1147
  if (!existsSync(agentCoordBin)) return;
1149
- // Pass the detected harness so a pruned Cursor/Codex heartbeat is recreated
1148
+ // Pass the detected adapter so a pruned Cursor/Codex heartbeat is recreated
1150
1149
  // with the correct platform; without it, healHeartbeat defaults to
1151
1150
  // claude_code and the dashboard mislabels the agent. See
1152
1151
  // heartbeat-writer.healHeartbeat.
1153
- spawnSync(agentCoordBin, ["heal-heartbeat", instanceId, sessionId, `--harness=${harness}`], {
1152
+ spawnSync(agentCoordBin, ["heal-heartbeat", instanceId, sessionId, `--adapter=${adapter}`], {
1154
1153
  encoding: "utf8",
1155
1154
  timeout: 2000,
1156
1155
  env: childEnv(coordRoot),
@@ -1158,38 +1157,59 @@ function healHeartbeatViaCli(
1158
1157
  }
1159
1158
 
1160
1159
  /**
1161
- * Walk up the ppid chain on Linux/WSL looking for the harness anchor PID,
1160
+ * Walk up the ppid chain on Linux/WSL looking for the adapter anchor PID,
1162
1161
  * the PID of the claude / cursor / codex binary. Finds the agent PID. Used by
1163
- * `tool.pre_use`'s pid-map self-heal so a re-parented harness binary (the
1162
+ * `tool.pre_use`'s pid-map self-heal so a re-parented adapter binary (the
1164
1163
  * VS Code 2.1.x sibling-claude spawn case) gets its pid-map row rewritten on
1165
1164
  * the next tool call rather than going invisible until SessionStart fires
1166
1165
  * again, which it may never do.
1167
1166
  *
1168
1167
  * Returns undefined only when no anchor is found; callers fall back to
1169
- * `process.ppid` (the bash wrapper's parent, which is usually the harness binary
1168
+ * `process.ppid` (the bash wrapper's parent, which is usually the adapter binary
1170
1169
  * itself). `HARNERY_AGENT_COORD_TEST_ANCHOR_PID` overrides everything so the
1171
1170
  * test sandbox can pin a deterministic PID.
1172
1171
  */
1173
- function findHarnessAnchorPid(harness?: Harness): number | undefined {
1172
+ function findAdapterAnchorPid(adapter?: Adapter): number | undefined {
1174
1173
  const override = coordEnv("AGENT_COORD_TEST_ANCHOR_PID");
1175
1174
  if (override) {
1176
1175
  const n = Number(override);
1177
1176
  if (Number.isFinite(n) && n > 0) return n;
1178
1177
  }
1178
+ // A adapter that states its own pid ends the search. Nothing inferred from the
1179
+ // process tree beats the adapter naming itself, and the inference is the part
1180
+ // that has been failing: comm matching wants a binary called after its
1181
+ // adapter, and one Claude Code build ships its CLI under a version-numbered
1182
+ // filename, so the walk found nothing and the caller fell back to the hook's
1183
+ // own shell. That row was dead within seconds, leaving every session in this
1184
+ // environment unattributed.
1185
+ const fromEnv = adapterPidFromEnv();
1186
+ if (fromEnv) return fromEnv;
1179
1187
  // Build the ppid chain (nearest → root, up to 20 hops), then hand it to the
1180
1188
  // pure selector. Linux/WSL reads /proc; macOS/BSD (no /proc) falls back to
1181
1189
  // `ps -o ppid=,comm=` parsed by the unit-tested `parsePsChainLine`. Splitting
1182
- // the walk (untestable off a live box) from the comm-matching keeps the
1183
- // cursor `node`-fallback logic verifiable.
1184
- const chain: Array<{ pid: number; comm: string }> = [];
1190
+ // the walk (untestable off a live box) from the matching keeps the selector
1191
+ // logic verifiable.
1192
+ //
1193
+ // Only the /proc branch carries an executable path for the selector's
1194
+ // path-based pass. Asking `ps` for one means either a second spawn per hop or
1195
+ // splitting `comm` from `args` on a line where comm may itself contain spaces,
1196
+ // and the adapter that needs the path pass states its pid in the env anyway.
1197
+ const chain: Array<{ pid: number; comm: string; exe?: string }> = [];
1185
1198
  let pid = process.pid;
1186
1199
  for (let hops = 0; hops < 20; hops++) {
1187
- let hop: { comm: string; ppid: number } | null = null;
1200
+ let hop: { comm: string; ppid: number; exe?: string } | null = null;
1188
1201
  try {
1189
1202
  const comm = readFileSync(`/proc/${pid}/comm`, "utf8").trim();
1190
1203
  const status = readFileSync(`/proc/${pid}/status`, "utf8");
1191
1204
  const m = status.match(/^PPid:\s+(\d+)/m);
1192
- hop = { comm, ppid: m ? Number(m[1]) : 0 };
1205
+ // argv[0], for the path-based second pass. cmdline is NUL-separated.
1206
+ let exe: string | undefined;
1207
+ try {
1208
+ exe = readFileSync(`/proc/${pid}/cmdline`, "utf8").split("\0")[0] || undefined;
1209
+ } catch {
1210
+ /* exe is optional */
1211
+ }
1212
+ hop = { comm, ppid: m ? Number(m[1]) : 0, exe };
1193
1213
  } catch {
1194
1214
  // no /proc (macOS/BSD) — fall through to ps
1195
1215
  }
@@ -1198,11 +1218,11 @@ function findHarnessAnchorPid(harness?: Harness): number | undefined {
1198
1218
  if (out.status === 0) hop = parsePsChainLine(out.stdout);
1199
1219
  }
1200
1220
  if (!hop) break;
1201
- chain.push({ pid, comm: hop.comm });
1221
+ chain.push({ pid, comm: hop.comm, exe: hop.exe });
1202
1222
  if (!Number.isFinite(hop.ppid) || hop.ppid === 0 || hop.ppid === 1) break;
1203
1223
  pid = hop.ppid;
1204
1224
  }
1205
- return selectAnchorPid(chain, harness);
1225
+ return selectAnchorPid(chain, adapter);
1206
1226
  }
1207
1227
 
1208
1228
  /**
@@ -1212,7 +1232,7 @@ function findHarnessAnchorPid(harness?: Harness): number | undefined {
1212
1232
  *
1213
1233
  * The pid argument prefers the payload's `pid` (CC populates it on
1214
1234
  * SessionStart and may also send it on PreToolUse), then
1215
- * `findHarnessAnchorPid`, then `process.ppid`. Writes go through the same
1235
+ * `findAdapterAnchorPid`, then `process.ppid`. Writes go through the same
1216
1236
  * idempotent `writePidmapViaAgentCoord` helper that SessionStart uses: no
1217
1237
  * disk I/O on no-op heals (when the row already points at us).
1218
1238
  *
@@ -1223,12 +1243,12 @@ function findHarnessAnchorPid(harness?: Harness): number | undefined {
1223
1243
  function refreshPidmap(
1224
1244
  coordRoot: string,
1225
1245
  instanceId: string,
1226
- harness: Harness,
1246
+ adapter: Adapter,
1227
1247
  payloadPid?: number,
1228
1248
  ): void {
1229
- const pid = payloadPid ?? findHarnessAnchorPid(harness) ?? process.ppid;
1249
+ const pid = payloadPid ?? findAdapterAnchorPid(adapter) ?? process.ppid;
1230
1250
  if (!Number.isFinite(pid) || pid <= 0) return;
1231
- writePidmapViaAgentCoord(coordRoot, pid, instanceId, harnessPlatform(harness));
1251
+ writePidmapViaAgentCoord(coordRoot, pid, instanceId, adapterPlatform(adapter));
1232
1252
  }
1233
1253
 
1234
1254
  function stampToolActivity(
@@ -1236,7 +1256,7 @@ function stampToolActivity(
1236
1256
  instanceId: string,
1237
1257
  data: Record<string, unknown>,
1238
1258
  ): void {
1239
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1259
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1240
1260
  if (!existsSync(agentCoordBin)) return;
1241
1261
  const toolName = (data.tool_name as string | undefined) ?? "";
1242
1262
  // Extract a 1-line target from the tool_input blob (file path / command head).
@@ -1308,7 +1328,7 @@ function releaseClaimOnFailure(
1308
1328
  : filePath;
1309
1329
  }
1310
1330
 
1311
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1331
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1312
1332
  if (!existsSync(agentCoordBin)) return;
1313
1333
  spawnSync(agentCoordBin, ["release-claim", instanceId, canonical], {
1314
1334
  encoding: "utf8",
@@ -1349,7 +1369,7 @@ function cleanupSessionEnd(coordRoot: string, instanceId: string, reason: string
1349
1369
  }
1350
1370
  }
1351
1371
  // Activity log
1352
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1372
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1353
1373
  if (existsSync(agentCoordBin)) {
1354
1374
  spawnSync(
1355
1375
  agentCoordBin,
@@ -1363,10 +1383,10 @@ async function emitUserPromptSubmitSystemMessage(
1363
1383
  coordRoot: string,
1364
1384
  instanceId: string,
1365
1385
  sessionId: string,
1366
- harness: Harness,
1386
+ adapter: Adapter,
1367
1387
  recoveryBriefing = "",
1368
1388
  ): Promise<boolean> {
1369
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1389
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1370
1390
  let additionalContext = "";
1371
1391
 
1372
1392
  if (existsSync(agentCoordBin)) {
@@ -1385,10 +1405,14 @@ async function emitUserPromptSubmitSystemMessage(
1385
1405
 
1386
1406
  const args = ["prompt-context", "--instance", instanceId, "--session", sessionId];
1387
1407
  if (agentName) args.push("--name", agentName);
1388
- // Cursor + Codex sessions get the set-task staleness nudge. CC enforces it
1389
- // via the Stop-hook transcript scan; the nudge replaces that for harnesses
1390
- // that don't reliably expose a transcript_path during stop.
1391
- if (harness === "cursor" || harness === "codex") args.push("--task-nudge");
1408
+ // Every human-facing adapter gets the first-session naming reminder from
1409
+ // the shared hook path. Cursor + Codex additionally get ongoing set-task
1410
+ // staleness nudges; Claude Code enforces those via its Stop transcript.
1411
+ // Codex gets a fresh status-footer reminder on every prompt. Its Stop hook
1412
+ // stays observe-only, so missing the footer never replaces the answer.
1413
+ args.push("--session-name-nudge");
1414
+ if (adapter === "cursor" || adapter === "codex") args.push("--task-nudge");
1415
+ if (adapter === "codex") args.push("--status-footer-nudge");
1392
1416
  const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
1393
1417
  if (result.status === 0 && result.stdout) additionalContext = result.stdout.trim();
1394
1418
  }
@@ -1397,8 +1421,8 @@ async function emitUserPromptSubmitSystemMessage(
1397
1421
  }
1398
1422
  if (!additionalContext) return false;
1399
1423
 
1400
- const { emitContext } = await import("./harness/output.ts");
1401
- emitContext(harness, "UserPromptSubmit", additionalContext);
1424
+ const { emitContext } = await import("./adapter/output.ts");
1425
+ emitContext(adapter, "UserPromptSubmit", additionalContext);
1402
1426
  return true;
1403
1427
  }
1404
1428
 
@@ -1407,14 +1431,14 @@ function emitSubagentStartContext(
1407
1431
  instanceId: string,
1408
1432
  sessionId: string,
1409
1433
  data: Record<string, unknown>,
1410
- harness: Harness,
1434
+ adapter: Adapter,
1411
1435
  ): void {
1412
1436
  // Look up the subagent's assigned name (just-written by agent-coord assignName
1413
1437
  // in session.start data) + the parent's short id for the "you are a subagent
1414
1438
  // of X" framing.
1415
1439
  const subagentName = (data.name as string | undefined) ?? "";
1416
1440
  if (!subagentName) return;
1417
- const platformLabel = harnessPlatform(harness);
1441
+ const platformLabel = adapterPlatform(adapter);
1418
1442
  const parentShort =
1419
1443
  sessionId && sessionId !== instanceId ? `agent-${sessionId.slice(0, 8)}` : "the parent session";
1420
1444
  const message = `You are agent-${subagentName} (${platformLabel} subagent). You're a subagent of ${parentShort}.`;
@@ -1422,7 +1446,7 @@ function emitSubagentStartContext(
1422
1446
  // Render peer table inline since the subagent might want to know who else
1423
1447
  // is around. Reuse prompt-context (which dedups against the per-owner hash);
1424
1448
  // first call will always emit.
1425
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1449
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1426
1450
  let combined = message;
1427
1451
  if (existsSync(agentCoordBin)) {
1428
1452
  const result = spawnSync(
@@ -1436,14 +1460,14 @@ function emitSubagentStartContext(
1436
1460
 
1437
1461
  // Use SubagentStart event-name in CC's hookSpecificOutput shape; cursor's
1438
1462
  // flat `additional_context` works the same way.
1439
- void import("./harness/output.ts").then(({ emitContext }) => {
1440
- emitContext(harness, "SubagentStart", combined);
1463
+ void import("./adapter/output.ts").then(({ emitContext }) => {
1464
+ emitContext(adapter, "SubagentStart", combined);
1441
1465
  });
1442
1466
  }
1443
1467
 
1444
- function harnessPlatform(harness: Harness): string {
1445
- if (harness === "claude-code") return "claude_code";
1446
- return harness;
1468
+ function adapterPlatform(adapter: Adapter): string {
1469
+ if (adapter === "claude-code") return "claude_code";
1470
+ return adapter;
1447
1471
  }
1448
1472
 
1449
1473
  async function emitSessionStartSystemMessage(
@@ -1451,10 +1475,10 @@ async function emitSessionStartSystemMessage(
1451
1475
  instanceId: string,
1452
1476
  sessionId: string,
1453
1477
  emittedData: Record<string, unknown>,
1454
- harness: Harness,
1478
+ adapter: Adapter,
1455
1479
  recoveryBriefing = "",
1456
1480
  ): Promise<boolean> {
1457
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1481
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1458
1482
  let additionalContext = "";
1459
1483
  if (existsSync(agentCoordBin)) {
1460
1484
  // Sync-project so the heartbeat exists for downstream readers (peer table,
@@ -1463,10 +1487,10 @@ async function emitSessionStartSystemMessage(
1463
1487
  // Stale-sweep dead peers before rendering peer table.
1464
1488
  spawnSync(agentCoordBin, ["stale-sweep"], { encoding: "utf8", timeout: 3000 });
1465
1489
 
1466
- // SESSION_START activity log line, fired across all harnesses.
1490
+ // SESSION_START activity log line, fired across all adapters.
1467
1491
  const model = (emittedData.model as string | undefined) ?? "unknown";
1468
1492
  const source = (emittedData.source as string | undefined) ?? "startup";
1469
- const platform = harnessPlatform(harness);
1493
+ const platform = adapterPlatform(adapter);
1470
1494
  spawnSync(
1471
1495
  agentCoordBin,
1472
1496
  [
@@ -1485,19 +1509,19 @@ async function emitSessionStartSystemMessage(
1485
1509
  // The "You are agent-X." prefix in session-context renders unqualified by
1486
1510
  // default (claude-code-style). For cursor/codex the bash dispatchers add
1487
1511
  // a "(Cursor)" / "(Codex)" suffix; pass it through as --platform-label.
1488
- if (harness !== "claude-code") {
1512
+ if (adapter !== "claude-code") {
1489
1513
  args.push("--platform-label", platform === "cursor" ? "Cursor" : "Codex");
1490
1514
  }
1491
1515
  const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
1492
1516
  if (result.status === 0 && result.stdout) additionalContext = result.stdout.trim();
1493
1517
  }
1494
1518
 
1495
- // Effect (claude-code): merge the scratch recovery cue into the session-start
1519
+ // Effect (claude-code): merge the journal recovery cue into the session-start
1496
1520
  // context. Was a standalone additionalContext emission from the previous
1497
- // scratch-on-start adapter; now that agent-hook is the single SessionStart
1521
+ // journal-on-start adapter; now that agent-hook is the single SessionStart
1498
1522
  // entry, it folds in here.
1499
- if (harness === "claude-code") {
1500
- const cue = scratchRecoveryCue(coordRoot);
1523
+ if (adapter === "claude-code") {
1524
+ const cue = journalRecoveryCue(coordRoot);
1501
1525
  if (cue) additionalContext = [additionalContext, cue].filter(Boolean).join("\n\n");
1502
1526
  }
1503
1527
  if (recoveryBriefing) {
@@ -1505,8 +1529,8 @@ async function emitSessionStartSystemMessage(
1505
1529
  }
1506
1530
  if (!additionalContext) return false;
1507
1531
 
1508
- const { emitContext } = await import("./harness/output.ts");
1509
- emitContext(harness, "SessionStart", additionalContext);
1532
+ const { emitContext } = await import("./adapter/output.ts");
1533
+ emitContext(adapter, "SessionStart", additionalContext);
1510
1534
  return true;
1511
1535
  }
1512
1536
 
@@ -1514,7 +1538,7 @@ function completeRecoveryInjection(
1514
1538
  coordRoot: string,
1515
1539
  instanceId: string,
1516
1540
  sessionId: string,
1517
- harness: Harness,
1541
+ adapter: Adapter,
1518
1542
  recovery: PreparedContextRecovery,
1519
1543
  injectionEvent: "SessionStart" | "UserPromptSubmit",
1520
1544
  ): void {
@@ -1523,7 +1547,7 @@ function completeRecoveryInjection(
1523
1547
  event_type: "context.recovery.injected",
1524
1548
  instance_id: instanceId,
1525
1549
  session_id: sessionId,
1526
- harness,
1550
+ adapter,
1527
1551
  data: {
1528
1552
  capsule_id: recovery.capsule.capsule_id,
1529
1553
  generation: recovery.capsule.generation,