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,25 +15,27 @@
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
  import { spawnSync } from "node:child_process";
21
21
  import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
22
22
  import { dirname, join } from "node:path";
23
23
  import { coordEnv } from "../../lib/env.js";
24
24
  import { replayCodexJsonl } from "../agents/codex-replay.js";
25
+ import { coordBinPath } from "../agents/coord-bin.js";
25
26
  import { consumeSince, writeCursor } from "../agents/events/consume.js";
26
27
  import { evaluateStopHook } from "../agents/rules/stop-hook.js";
27
28
  import { projectHeartbeats } from "../agents/state/heartbeat-projector.js";
29
+ import { writePidmapRow } from "../agents/state/pidmap.js";
28
30
  import { shellMutationPaths } from "../agents/state/shell-mutation.js";
29
31
  import { checkpointContext, completeContextRecovery, extractContextSample, markContextCompactionCompleted, prepareContextRecovery, readContextState, recordContextSample, } from "../context/index.js";
30
32
  import { ensureRelayDaemon, fetchPresence, publishPresence } from "../presence/index.js";
31
- import { captureImages, detectPresence, imageJanitor, playSound, resetSoundCounters, runSessionSyncExtension, runTurnSummary, scratchArchive, scratchJanitor, scratchRecoveryCue, soundForEvent, } from "./effects/index.js";
33
+ import { detectAdapter } from "./adapter/detect.js";
34
+ import { extractBashCommand, extractToolDescription, normalizeEventName, parsePayload, } from "./adapter/parse.js";
35
+ import { captureImages, detectPresence, imageJanitor, journalArchive, journalJanitor, journalRecoveryCue, playSound, resetSoundCounters, runSessionSyncExtension, runTurnSummary, soundForEvent, } from "./effects/index.js";
32
36
  import { emit } from "./events/emit.js";
33
37
  import { canonicalize } from "./guard-path.js";
34
- import { detectHarness } from "./harness/detect.js";
35
- import { extractBashCommand, extractToolDescription, normalizeEventName, parsePayload, } from "./harness/parse.js";
36
- import { parsePsChainLine, selectAnchorPid } from "./resolve/anchor.js";
38
+ import { adapterPidFromEnv, parsePsChainLine, selectAnchorPid } from "./resolve/anchor.js";
37
39
  import { findCoordRoot } from "./resolve/coord-root.js";
38
40
  import { extractIntentComment, resolveIntent } from "./resolve/intent.js";
39
41
  import { resolveOwner } from "./resolve/owner.js";
@@ -42,11 +44,11 @@ function parseArgv(argv) {
42
44
  const out = { eventName: null, extra: [] };
43
45
  for (let i = 0; i < argv.length; i++) {
44
46
  const arg = argv[i];
45
- if (arg === "--harness") {
46
- i++; // detectHarness will re-parse; just consume the value here.
47
+ if (arg === "--adapter") {
48
+ i++; // detectAdapter will re-parse; just consume the value here.
47
49
  continue;
48
50
  }
49
- if (arg.startsWith("--harness="))
51
+ if (arg.startsWith("--adapter="))
50
52
  continue;
51
53
  if (!out.eventName && !arg.startsWith("--")) {
52
54
  out.eventName = arg;
@@ -74,7 +76,7 @@ async function readStdin() {
74
76
  /**
75
77
  * Env for child agent-coord spawns, with the coord root pinned. The hook
76
78
  * process may be running with the session shell's cwd (inside a submodule or
77
- * scratch dir), and agent-coord resolves its root from cwd unless overridden —
79
+ * journal dir), and agent-coord resolves its root from cwd unless overridden —
78
80
  * without the pin a child could write state to a different .harnery than the
79
81
  * one this hook resolved.
80
82
  */
@@ -111,13 +113,13 @@ function logError(coordRoot, err, context) {
111
113
  /**
112
114
  * Spawn `agent-coord assign-name <owner> <kind>` to mint or recover the
113
115
  * hurricane-style name for this owner. Returns null on any failure so
114
- * session.start emission never breaks the harness flow.
116
+ * session.start emission never breaks the adapter flow.
115
117
  *
116
118
  * Lives at agent-hooks side (not agent-coord) to keep emitter/consumer
117
119
  * separation: we spawn rather than import.
118
120
  */
119
121
  function assignNameViaAgentCoord(coordRoot, instanceId, kind) {
120
- const binary = join(coordRoot, "harnery", "bin", "agent-coord");
122
+ const binary = coordBinPath("agent-coord", coordRoot) ?? "";
121
123
  if (!existsSync(binary))
122
124
  return null;
123
125
  try {
@@ -139,35 +141,22 @@ function assignNameViaAgentCoord(coordRoot, instanceId, kind) {
139
141
  }
140
142
  }
141
143
  /**
142
- * Direct (in-process) pidmap write, avoids the spawn overhead of going via
143
- * the agent-coord CLI for every session.start / subagent.start. Pid-map
144
- * rows are essential for `harn agents whoami` ppid resolution.
144
+ * Direct (in-process) pidmap write, avoiding the spawn overhead of going via
145
+ * the agent-coord CLI for every session.start / subagent.start. Pid-map rows
146
+ * are essential for `harn agents whoami` ppid resolution.
147
+ *
148
+ * This used to inline its own copy of the write to keep this module's
149
+ * dependencies narrow, which quietly mattered: the shared writer is where row
150
+ * hygiene lives, so the duplicate meant the only hot write path in the system
151
+ * never swept dead rows, and the map grew unbounded. It calls the shared writer
152
+ * now, and this module already imports from that directory anyway.
145
153
  */
146
154
  function writePidmapViaAgentCoord(coordRoot, pid, instanceId, platform) {
147
155
  try {
148
- // Inline write: same atomic temp+rename pattern as
149
- // agent-coord/src/state/pidmap.ts but skips importing across module
150
- // boundaries to keep agent-hooks's deps explicit.
151
- const dir = join(coordRoot, ".harnery", "pid-map");
152
- const path = join(dir, String(pid));
153
- const row = `${instanceId}\t${platform}`;
154
- if (existsSync(path)) {
155
- try {
156
- const current = require("node:fs").readFileSync(path, "utf8");
157
- if (current === row)
158
- return;
159
- }
160
- catch {
161
- /* fall through */
162
- }
163
- }
164
- mkdirSync(dir, { recursive: true });
165
- const tmp = `${path}.tmp.${process.pid}`;
166
- require("node:fs").writeFileSync(tmp, row, "utf8");
167
- require("node:fs").renameSync(tmp, path);
156
+ writePidmapRow(coordRoot, pid, instanceId, platform);
168
157
  }
169
158
  catch {
170
- /* never break the harness flow */
159
+ /* never break the adapter flow */
171
160
  }
172
161
  }
173
162
  function clampString(s, max) {
@@ -188,23 +177,23 @@ function buildEventData(eventType, ctx) {
188
177
  const p = ctx.payload;
189
178
  switch (eventType) {
190
179
  case "session.start": {
191
- const harnessPlatform = ctx.harness === "claude-code"
180
+ const adapterPlatform = ctx.adapter === "claude-code"
192
181
  ? "claude_code"
193
- : ctx.harness === "cursor"
182
+ : ctx.adapter === "cursor"
194
183
  ? "cursor"
195
184
  : "codex";
196
185
  // Assign (or recover) name + kind via agent-coord. Idempotent: resume
197
186
  // returns the original name; new owner consumes a counter slot.
198
187
  const assigned = assignNameViaAgentCoord(ctx.coordRoot, ctx.instanceId, "session");
199
- // Write the harness pid-map row so `harn agents whoami` ppid-walks find
188
+ // Write the adapter pid-map row so `harn agents whoami` ppid-walks find
200
189
  // this owner. Prefer the payload pid (the actual claude binary), then the
201
190
  // anchor walk (the `node` ancestor for Cursor, which has no payload pid),
202
191
  // then our own process.ppid. Without the anchor, Cursor anchored on the
203
192
  // ephemeral hook bash parent, a PID that dies before the agent's next
204
193
  // shell tool call, so the ppid walk found nothing (no_pidmap_entry).
205
- const harnessPid = p?.pid ?? findHarnessAnchorPid(ctx.harness) ?? process.ppid;
206
- if (harnessPid) {
207
- writePidmapViaAgentCoord(ctx.coordRoot, harnessPid, ctx.instanceId, harnessPlatform);
194
+ const adapterPid = p?.pid ?? findAdapterAnchorPid(ctx.adapter) ?? process.ppid;
195
+ if (adapterPid) {
196
+ writePidmapViaAgentCoord(ctx.coordRoot, adapterPid, ctx.instanceId, adapterPlatform);
208
197
  }
209
198
  return {
210
199
  started_at: new Date().toISOString(),
@@ -213,17 +202,25 @@ function buildEventData(eventType, ctx) {
213
202
  // supply it). Fall back to the transcript, populated on `resume`, and
214
203
  // backfilled later by `turn.stop` for a fresh `startup` session.
215
204
  model: p?.model ?? scanTranscriptModel(p?.transcript_path),
216
- pid: harnessPid,
205
+ pid: adapterPid,
217
206
  source: p?.source,
218
- platform: harnessPlatform,
207
+ platform: adapterPlatform,
219
208
  name: assigned?.name,
220
209
  kind: "session",
221
210
  agent_id: ctx.instanceId,
222
211
  // Workflow-child linkage: `workflow run` children carry the run id in
223
212
  // env (spawn adapters set it via buildChildEnv), so their sessions and
224
- // heartbeats join back to the run journal + /workflows web view.
213
+ // heartbeats join back to the run transcript + /workflows web view.
225
214
  ...(coordEnv("WORKFLOW_CHILD") === "1" && coordEnv("WORKFLOW_RUN_ID")
226
- ? { workflow_run_id: coordEnv("WORKFLOW_RUN_ID") }
215
+ ? {
216
+ workflow_run_id: coordEnv("WORKFLOW_RUN_ID"),
217
+ // Which agent row of that run this session is. The orchestrator
218
+ // stamps it on the way in, because the adapter does not report a
219
+ // session id until the agent has already finished.
220
+ ...(coordEnv("WORKFLOW_AGENT_ID")
221
+ ? { workflow_agent_id: coordEnv("WORKFLOW_AGENT_ID") }
222
+ : {}),
223
+ }
227
224
  : {}),
228
225
  };
229
226
  }
@@ -239,7 +236,7 @@ function buildEventData(eventType, ctx) {
239
236
  }
240
237
  case "turn.stop": {
241
238
  return {
242
- // Backfill the model for harnesses that omit it at session.start
239
+ // Backfill the model for adapters that omit it at session.start
243
240
  // (Claude Code). The transcript is populated with assistant turns by
244
241
  // Stop-hook time, so this resolves even for fresh `startup` sessions.
245
242
  model: p?.model ?? scanTranscriptModel(p?.transcript_path),
@@ -363,13 +360,13 @@ function numberField(value) {
363
360
  }
364
361
  async function main() {
365
362
  const { eventName, extra } = parseArgv(process.argv.slice(2));
366
- const harness = detectHarness(process.argv.slice(2));
363
+ const adapter = detectAdapter(process.argv.slice(2));
367
364
  const raw = await readStdin();
368
365
  // Kill-switch-INDEPENDENT effects: notification sounds fire BEFORE the
369
366
  // HARNERY_AGENT_COORD_OFF gate so audible feedback survives incident-triage
370
367
  // bypass: sound playback happens before the kill-switch bailout.
371
368
  // Claude-Code-only; stop-failure → error, sub-agent-start → subagent-start.
372
- if (harness === "claude-code" && eventName) {
369
+ if (adapter === "claude-code" && eventName) {
373
370
  const s = soundForEvent(eventName);
374
371
  if (s) {
375
372
  const repoRoot = findCoordRoot(process.cwd());
@@ -401,15 +398,15 @@ async function main() {
401
398
  const debugBase = {
402
399
  ts: new Date().toISOString(),
403
400
  event_name: eventName,
404
- harness,
401
+ adapter,
405
402
  extra_argv: extra,
406
403
  payload_bytes: raw.length,
407
404
  cwd: process.cwd(),
408
405
  pid: process.pid,
409
406
  ppid: process.ppid,
410
407
  };
411
- if (!eventName || !harness) {
412
- appendDebug(coordRoot, { ...debugBase, skipped: "missing-event-or-harness" });
408
+ if (!eventName || !adapter) {
409
+ appendDebug(coordRoot, { ...debugBase, skipped: "missing-event-or-adapter" });
413
410
  return 0;
414
411
  }
415
412
  const norm = normalizeEventName(eventName);
@@ -417,7 +414,7 @@ async function main() {
417
414
  appendDebug(coordRoot, { ...debugBase, skipped: "non-canonical-event" });
418
415
  return 0;
419
416
  }
420
- const payload = parsePayload(raw, harness);
417
+ const payload = parsePayload(raw, adapter);
421
418
  const owner = resolveOwner({ payload: payload?.raw ?? null, coordRoot });
422
419
  if (!owner) {
423
420
  appendDebug(coordRoot, {
@@ -432,7 +429,7 @@ async function main() {
432
429
  coordRoot,
433
430
  payload,
434
431
  raw,
435
- harness,
432
+ adapter,
436
433
  instanceId: owner.instance_id,
437
434
  });
438
435
  const envelope = emit(coordRoot, {
@@ -442,7 +439,7 @@ async function main() {
442
439
  parent_session_id: payload?.parent_session_id,
443
440
  turn_id: payload?.turn_id,
444
441
  parent_turn_id: payload?.parent_turn_id,
445
- harness,
442
+ adapter,
446
443
  data,
447
444
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
448
445
  });
@@ -453,13 +450,13 @@ async function main() {
453
450
  event_id: envelope.event_id,
454
451
  });
455
452
  // Context telemetry is opportunistic and truthful: only persist a sample
456
- // when the harness payload actually exposes usage/window data. Identical
453
+ // when the adapter payload actually exposes usage/window data. Identical
457
454
  // measurements are de-duplicated before they reach the canonical stream.
458
455
  if (payload?.raw) {
459
456
  try {
460
457
  const sample = extractContextSample(payload.raw, {
461
458
  sessionId,
462
- harness,
459
+ adapter,
463
460
  model: payload.model,
464
461
  source: "hook",
465
462
  confidence: "reported",
@@ -471,7 +468,7 @@ async function main() {
471
468
  event_type: "context.sampled",
472
469
  instance_id: owner.instance_id,
473
470
  session_id: sessionId,
474
- harness,
471
+ adapter,
475
472
  data: {
476
473
  model: sample.model,
477
474
  used_tokens: sample.used_tokens,
@@ -490,13 +487,13 @@ async function main() {
490
487
  }
491
488
  // A native pre-compaction signal is the safest available point to capture
492
489
  // external work state. The operation is idempotent until recovery, so a
493
- // harness retry cannot create a storm of near-identical capsules.
490
+ // adapter retry cannot create a storm of near-identical capsules.
494
491
  if (norm.event_type === "context.compaction.started") {
495
492
  try {
496
493
  const checkpoint = checkpointContext(coordRoot, {
497
494
  sessionId,
498
495
  instanceId: owner.instance_id,
499
- harness,
496
+ adapter,
500
497
  cwd: payload?.cwd ?? process.cwd(),
501
498
  reason: "pre_compact",
502
499
  model: payload?.model,
@@ -505,7 +502,7 @@ async function main() {
505
502
  event_type: "context.checkpoint.created",
506
503
  instance_id: owner.instance_id,
507
504
  session_id: sessionId,
508
- harness,
505
+ adapter,
509
506
  data: {
510
507
  capsule_id: checkpoint.capsule.capsule_id,
511
508
  generation: checkpoint.capsule.generation,
@@ -531,18 +528,18 @@ async function main() {
531
528
  }
532
529
  }
533
530
  // Phase 8: SessionStart post-emit: project the event so the heartbeat
534
- // lands synchronously, run stale-sweep, and emit the harness-shaped
531
+ // lands synchronously, run stale-sweep, and emit the adapter-shaped
535
532
  // systemMessage JSON (peer table + wiring check + council invites).
536
- // Harness-agnostic since v0.5.0; replaces the previous bash UX layer
537
- // and the equivalent per-harness bash session_start handlers.
533
+ // Adapter-agnostic since v0.5.0; replaces the previous bash UX layer
534
+ // and the equivalent per-adapter bash session_start handlers.
538
535
  if (norm.event_type === "session.start") {
539
- // Effect (claude-code): prune stale scratch archives + sweep orphans.
536
+ // Effect (claude-code): prune stale journal archives + sweep orphans.
540
537
  // The recovery-cue is merged into the
541
538
  // session-start additionalContext inside emitSessionStartSystemMessage.
542
- if (harness === "claude-code")
543
- scratchJanitor(coordRoot);
544
- // Image-feed retention sweep (size + age cap on .harnery/images/). Harness-
545
- // agnostic, cheap (one readdir), fail-soft. Paired with scratchJanitor as a
539
+ if (adapter === "claude-code")
540
+ journalJanitor(coordRoot);
541
+ // Image-feed retention sweep (size + age cap on .harnery/images/). Adapter-
542
+ // agnostic, cheap (one readdir), fail-soft. Paired with journalJanitor as a
546
543
  // session-start "tidy the coord layer" step.
547
544
  try {
548
545
  imageJanitor(coordRoot);
@@ -557,7 +554,7 @@ async function main() {
557
554
  event_type: "context.compaction.completed",
558
555
  instance_id: owner.instance_id,
559
556
  session_id: sessionId,
560
- harness,
557
+ adapter,
561
558
  data: { trigger: "auto" },
562
559
  });
563
560
  markContextCompactionCompleted(coordRoot, {
@@ -575,9 +572,9 @@ async function main() {
575
572
  }
576
573
  }
577
574
  try {
578
- const injected = await emitSessionStartSystemMessage(coordRoot, owner.instance_id, sessionId, data, harness, recovery?.briefing ?? "");
575
+ const injected = await emitSessionStartSystemMessage(coordRoot, owner.instance_id, sessionId, data, adapter, recovery?.briefing ?? "");
579
576
  if (injected && recovery) {
580
- completeRecoveryInjection(coordRoot, owner.instance_id, sessionId, harness, recovery, "SessionStart");
577
+ completeRecoveryInjection(coordRoot, owner.instance_id, sessionId, adapter, recovery, "SessionStart");
581
578
  }
582
579
  }
583
580
  catch (err) {
@@ -595,7 +592,7 @@ async function main() {
595
592
  logError(coordRoot, err, { phase: "session-start-presence" });
596
593
  }
597
594
  }
598
- // Phase 8: SessionEnd cleanup: delete heartbeat + pid-map rows. Harness-
595
+ // Phase 8: SessionEnd cleanup: delete heartbeat + pid-map rows. Adapter-
599
596
  // agnostic since v0.5.0.
600
597
  if (norm.event_type === "session.end") {
601
598
  try {
@@ -604,10 +601,10 @@ async function main() {
604
601
  catch (err) {
605
602
  logError(coordRoot, err, { phase: "session-end-cleanup" });
606
603
  }
607
- // Effects (claude-code): archive the ending agent's scratchpad + force a
604
+ // Effects (claude-code): archive the ending agent's journal + force a
608
605
  // session-telemetry sync (via HARNERY_CLAUDE_SESSIONS_FORCE=1).
609
- if (harness === "claude-code") {
610
- scratchArchive(coordRoot, owner.instance_id);
606
+ if (adapter === "claude-code") {
607
+ journalArchive(coordRoot, owner.instance_id);
611
608
  runSessionSyncExtension(coordRoot, true);
612
609
  }
613
610
  // Presence: publish the post-cleanup state so peers see this session gone
@@ -624,7 +621,7 @@ async function main() {
624
621
  // subagent (claude-code + cursor; codex doesn't fan out subagents today).
625
622
  if (norm.event_type === "subagent.start") {
626
623
  try {
627
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
624
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
628
625
  if (existsSync(agentCoordBin)) {
629
626
  spawnSync(agentCoordBin, ["project"], {
630
627
  encoding: "utf8",
@@ -633,12 +630,12 @@ async function main() {
633
630
  });
634
631
  spawnSync(agentCoordBin, [
635
632
  "log",
636
- `SUBAGENT_START agent_type=${data.agent_type ?? "unknown"} agent_id=${owner.instance_id.slice(0, 8)} platform=${harnessPlatform(harness)}`,
633
+ `SUBAGENT_START agent_type=${data.agent_type ?? "unknown"} agent_id=${owner.instance_id.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
637
634
  "--instance",
638
635
  owner.instance_id,
639
636
  ], { encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) });
640
637
  }
641
- emitSubagentStartContext(coordRoot, owner.instance_id, sessionId, data, harness);
638
+ emitSubagentStartContext(coordRoot, owner.instance_id, sessionId, data, adapter);
642
639
  }
643
640
  catch (err) {
644
641
  logError(coordRoot, err, { phase: "subagent-start-project" });
@@ -648,11 +645,11 @@ async function main() {
648
645
  if (norm.event_type === "subagent.stop") {
649
646
  try {
650
647
  cleanupSessionEnd(coordRoot, owner.instance_id, data.reason ?? "unknown");
651
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
648
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
652
649
  if (existsSync(agentCoordBin)) {
653
650
  spawnSync(agentCoordBin, [
654
651
  "log",
655
- `SUBAGENT_STOP agent_id=${owner.instance_id.slice(0, 8)} platform=${harnessPlatform(harness)}`,
652
+ `SUBAGENT_STOP agent_id=${owner.instance_id.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
656
653
  "--instance",
657
654
  owner.instance_id,
658
655
  ], { encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) });
@@ -663,11 +660,11 @@ async function main() {
663
660
  }
664
661
  }
665
662
  // Phase 8: UserPromptSubmit: render dedup'd peer table + council pending
666
- // and emit the harness-shaped systemMessage JSON. Harness-agnostic since v0.5.0.
663
+ // and emit the adapter-shaped systemMessage JSON. Adapter-agnostic since v0.5.0.
667
664
  if (norm.event_type === "user_prompt.submit") {
668
665
  // Effects (claude-code): reset per-turn sound rate-limit counters + run
669
666
  // presence detection on the prompt.
670
- if (harness === "claude-code") {
667
+ if (adapter === "claude-code") {
671
668
  resetSoundCounters(sessionId);
672
669
  const prompt = payload?.raw?.prompt ?? "";
673
670
  if (prompt)
@@ -697,9 +694,9 @@ async function main() {
697
694
  }
698
695
  }
699
696
  try {
700
- const injected = await emitUserPromptSubmitSystemMessage(coordRoot, owner.instance_id, sessionId, harness, recovery?.briefing ?? "");
697
+ const injected = await emitUserPromptSubmitSystemMessage(coordRoot, owner.instance_id, sessionId, adapter, recovery?.briefing ?? "");
701
698
  if (injected && recovery) {
702
- completeRecoveryInjection(coordRoot, owner.instance_id, sessionId, harness, recovery, "UserPromptSubmit");
699
+ completeRecoveryInjection(coordRoot, owner.instance_id, sessionId, adapter, recovery, "UserPromptSubmit");
703
700
  }
704
701
  }
705
702
  catch (err) {
@@ -707,7 +704,7 @@ async function main() {
707
704
  }
708
705
  }
709
706
  // turn.stop: telemetry + turn-summary effects, then the stop verdict. The
710
- // verdict + codex-replay previously lived in the per-harness shell adapters;
707
+ // verdict + codex-replay previously lived in the per-adapter shell adapters;
711
708
  // agent-hook owns them now. Runs on the normal "stop" event only;
712
709
  // "stop-failure" (API error) gets no gate, matching the previous
713
710
  // stop vs stop-failure split.
@@ -716,7 +713,7 @@ async function main() {
716
713
  // the status_checked / task_set / status_box_present evidence (codex
717
714
  // doesn't emit those live; this re-emits turn.stop after agent-hook's own,
718
715
  // so the verdict reads the replay's box signal as the latest).
719
- if (harness === "codex" && payload?.transcript_path && existsSync(payload.transcript_path)) {
716
+ if (adapter === "codex" && payload?.transcript_path && existsSync(payload.transcript_path)) {
720
717
  try {
721
718
  replayCodexJsonl({
722
719
  coordRoot,
@@ -732,14 +729,14 @@ async function main() {
732
729
  }
733
730
  // CC effects: rate-limited session-telemetry sync + turn-summary Haiku
734
731
  // auto-summary.
735
- if (harness === "claude-code") {
732
+ if (adapter === "claude-code") {
736
733
  runSessionSyncExtension(coordRoot, false);
737
734
  runTurnSummary(coordRoot, owner.instance_id, sessionId, payload?.transcript_path);
738
735
  }
739
736
  // Master-state heartbeat projection. Drains events.ndjson since the last
740
737
  // cursor → per-owner heartbeats. Was a SECOND binary (`agent-coord project`)
741
738
  // pinned to Claude Code Stop only; folded in here so it (a) is one
742
- // entry per event like everything else and (b) fires on EVERY harness's stop,
739
+ // entry per event like everything else and (b) fires on EVERY adapter's stop,
743
740
  // not just CC. Runs unconditionally before the verdict's possible exit-2 return
744
741
  // (the events are real regardless of whether the agent gets nagged), and after
745
742
  // codex-replay above so codex's replayed events are included in the drain.
@@ -771,21 +768,21 @@ async function main() {
771
768
  rule: "stop-hook",
772
769
  instance_id: owner.instance_id,
773
770
  session_id: sessionId,
774
- harness,
771
+ adapter,
775
772
  bypass: coordEnv("AGENT_COORD_BYPASS_STOP") === "1",
776
773
  workflow_child: coordEnv("WORKFLOW_CHILD") === "1",
777
774
  });
778
775
  if (!verdict.allow) {
779
- // Harness-aware enforcement channel: Claude Code / Codex honor exit-2 +
776
+ // Adapter-aware enforcement channel: Claude Code / Codex honor exit-2 +
780
777
  // stderr as a turn block; Cursor ignores exit codes (fail-open) and
781
778
  // re-prompts only via a `followup_message` it auto-submits. emitStopBlock
782
779
  // writes the right shape and returns the exit code to use.
783
- const { emitStopBlock } = await import("./harness/output.js");
784
- return emitStopBlock(harness, verdict);
780
+ const { emitStopBlock } = await import("./adapter/output.js");
781
+ return emitStopBlock(adapter, verdict);
785
782
  }
786
783
  }
787
784
  // Phase 7: PreToolUse: heartbeat + pid-map self-heal on every tool call.
788
- // Harness-agnostic: both writes have the same shape regardless of who fired.
785
+ // Adapter-agnostic: both writes have the same shape regardless of who fired.
789
786
  // Cursor/Codex bash dispatchers still fire their own G-guard logic, but the
790
787
  // heals here keep the agent-coord layer's view of liveness fresh.
791
788
  //
@@ -795,8 +792,8 @@ async function main() {
795
792
  // call was restored here afterward.
796
793
  if (norm.event_type === "tool.pre_use") {
797
794
  try {
798
- healHeartbeatViaCli(coordRoot, owner.instance_id, sessionId, harness);
799
- refreshPidmap(coordRoot, owner.instance_id, harness, payload?.pid);
795
+ healHeartbeatViaCli(coordRoot, owner.instance_id, sessionId, adapter);
796
+ refreshPidmap(coordRoot, owner.instance_id, adapter, payload?.pid);
800
797
  }
801
798
  catch (err) {
802
799
  logError(coordRoot, err, { phase: "pre-tool-use-heal" });
@@ -810,49 +807,49 @@ async function main() {
810
807
  payload,
811
808
  instanceId: owner.instance_id,
812
809
  sessionId,
813
- harness,
810
+ adapter,
814
811
  });
815
812
  }
816
813
  catch (err) {
817
814
  logError(coordRoot, err, { phase: "pre-tool-use-image-capture" });
818
815
  }
819
- // G-guard for ALL harnesses. Claude Code previously ran this via a
816
+ // G-guard for ALL adapters. Claude Code previously ran this via a
820
817
  // pre-tool-use bash adapter (which called `agent-coord verdict --rule=claim`);
821
- // that adapter is now deleted, so agent-hook owns the deny for every harness.
822
- // emitDeny() inside emits the harness-shaped permission JSON (claude-code +
818
+ // that adapter is now deleted, so agent-hook owns the deny for every adapter.
819
+ // emitDeny() inside emits the adapter-shaped permission JSON (claude-code +
823
820
  // codex use hookSpecificOutput.permissionDecision; cursor uses .permission).
824
821
  // apply_patch (codex) parses paths from the patch body and runs verdict
825
822
  // per-path; Edit/Write/NotebookEdit resolve a single target. Non-write tools
826
823
  // (incl. Agent) yield no targets and pass through with no deny.
827
824
  try {
828
- await runPreToolUseGuard(coordRoot, owner.instance_id, sessionId, data, harness);
825
+ await runPreToolUseGuard(coordRoot, owner.instance_id, sessionId, data, adapter);
829
826
  }
830
827
  catch (err) {
831
828
  logError(coordRoot, err, { phase: "pre-tool-use-guard" });
832
829
  }
833
830
  // Shell-mutation warn (warn-only, never blocks). Was the cursor
834
831
  // beforeShellExecution + codex preToolUse-Bash shell-mutation-claim-log in
835
- // the per-harness shell adapters. Cursor sends the command at payload.command;
832
+ // the per-adapter shell adapters. Cursor sends the command at payload.command;
836
833
  // codex Bash at tool_input.command. Emits a decision.warn per candidate-mutated
837
834
  // path so a peer sees the write in events.ndjson. (CC never did this,
838
835
  // preserved; it emits with its own hooks-side emitter per the
839
836
  // independent-emitter rule.)
840
837
  const shellCmd = eventName === "before-shell-execution"
841
838
  ? (payload?.raw.command ?? "")
842
- : harness === "codex" && data.tool_name === "Bash"
839
+ : adapter === "codex" && data.tool_name === "Bash"
843
840
  ? (payload?.raw.tool_input?.command ?? "")
844
841
  : "";
845
842
  if (shellCmd) {
846
843
  try {
847
844
  const paths = shellMutationPaths(shellCmd, coordRoot);
848
845
  const truncated = shellCmd.length > 80 ? shellCmd.slice(0, 80) : shellCmd;
849
- const platform = harnessPlatform(harness);
846
+ const platform = adapterPlatform(adapter);
850
847
  for (const p of paths) {
851
848
  emit(coordRoot, {
852
849
  event_type: "decision.warn",
853
850
  instance_id: owner.instance_id,
854
851
  session_id: sessionId,
855
- harness,
852
+ adapter,
856
853
  data: {
857
854
  rule: "shell_mutation_candidate",
858
855
  reason: `path=${p} cmd=${truncated} platform=${platform}`,
@@ -867,7 +864,7 @@ async function main() {
867
864
  }
868
865
  }
869
866
  // Phase 7: PostToolUse: stamp last_tool + last_tool_target on heartbeat.
870
- // Harness-agnostic for the same reason as tool.pre_use above.
867
+ // Adapter-agnostic for the same reason as tool.pre_use above.
871
868
  if (norm.event_type === "tool.post_use") {
872
869
  try {
873
870
  stampToolActivity(coordRoot, owner.instance_id, data);
@@ -885,7 +882,7 @@ async function main() {
885
882
  payload,
886
883
  instanceId: owner.instance_id,
887
884
  sessionId,
888
- harness,
885
+ adapter,
889
886
  });
890
887
  }
891
888
  catch (err) {
@@ -893,7 +890,7 @@ async function main() {
893
890
  }
894
891
  }
895
892
  // Phase 7: PostToolUseFailure: release claim on failed Edit (the file
896
- // never landed; the claim is stale). Harness-agnostic.
893
+ // never landed; the claim is stale). Adapter-agnostic.
897
894
  if (norm.event_type === "tool.post_use_failure") {
898
895
  try {
899
896
  releaseClaimOnFailure(coordRoot, owner.instance_id, data, payload?.raw);
@@ -904,14 +901,14 @@ async function main() {
904
901
  }
905
902
  return 0;
906
903
  }
907
- async function runPreToolUseGuard(coordRoot, instanceId, sessionId, data, harness) {
904
+ async function runPreToolUseGuard(coordRoot, instanceId, sessionId, data, adapter) {
908
905
  const toolName = data.tool_name ?? "";
909
906
  const targets = collectGuardTargets(toolName, data)
910
907
  .map((p) => canonicalize(coordRoot, p))
911
908
  .filter((p) => p !== null);
912
909
  if (targets.length === 0)
913
910
  return;
914
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
911
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
915
912
  if (!existsSync(agentCoordBin))
916
913
  return;
917
914
  // For apply_patch (multi-file), collect siblings so the deny reason names
@@ -949,8 +946,8 @@ async function runPreToolUseGuard(coordRoot, instanceId, sessionId, data, harnes
949
946
  reason += ` The patch also touched: ${siblings}: pick a different file or wait.`;
950
947
  }
951
948
  }
952
- const { emitDeny } = await import("./harness/output.js");
953
- emitDeny(harness, reason);
949
+ const { emitDeny } = await import("./adapter/output.js");
950
+ emitDeny(adapter, reason);
954
951
  return;
955
952
  }
956
953
  }
@@ -1011,45 +1008,60 @@ function parseApplyPatchPaths(data) {
1011
1008
  }
1012
1009
  return out;
1013
1010
  }
1014
- function healHeartbeatViaCli(coordRoot, instanceId, sessionId, harness) {
1015
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1011
+ function healHeartbeatViaCli(coordRoot, instanceId, sessionId, adapter) {
1012
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1016
1013
  if (!existsSync(agentCoordBin))
1017
1014
  return;
1018
- // Pass the detected harness so a pruned Cursor/Codex heartbeat is recreated
1015
+ // Pass the detected adapter so a pruned Cursor/Codex heartbeat is recreated
1019
1016
  // with the correct platform; without it, healHeartbeat defaults to
1020
1017
  // claude_code and the dashboard mislabels the agent. See
1021
1018
  // heartbeat-writer.healHeartbeat.
1022
- spawnSync(agentCoordBin, ["heal-heartbeat", instanceId, sessionId, `--harness=${harness}`], {
1019
+ spawnSync(agentCoordBin, ["heal-heartbeat", instanceId, sessionId, `--adapter=${adapter}`], {
1023
1020
  encoding: "utf8",
1024
1021
  timeout: 2000,
1025
1022
  env: childEnv(coordRoot),
1026
1023
  });
1027
1024
  }
1028
1025
  /**
1029
- * Walk up the ppid chain on Linux/WSL looking for the harness anchor PID,
1026
+ * Walk up the ppid chain on Linux/WSL looking for the adapter anchor PID,
1030
1027
  * the PID of the claude / cursor / codex binary. Finds the agent PID. Used by
1031
- * `tool.pre_use`'s pid-map self-heal so a re-parented harness binary (the
1028
+ * `tool.pre_use`'s pid-map self-heal so a re-parented adapter binary (the
1032
1029
  * VS Code 2.1.x sibling-claude spawn case) gets its pid-map row rewritten on
1033
1030
  * the next tool call rather than going invisible until SessionStart fires
1034
1031
  * again, which it may never do.
1035
1032
  *
1036
1033
  * Returns undefined only when no anchor is found; callers fall back to
1037
- * `process.ppid` (the bash wrapper's parent, which is usually the harness binary
1034
+ * `process.ppid` (the bash wrapper's parent, which is usually the adapter binary
1038
1035
  * itself). `HARNERY_AGENT_COORD_TEST_ANCHOR_PID` overrides everything so the
1039
1036
  * test sandbox can pin a deterministic PID.
1040
1037
  */
1041
- function findHarnessAnchorPid(harness) {
1038
+ function findAdapterAnchorPid(adapter) {
1042
1039
  const override = coordEnv("AGENT_COORD_TEST_ANCHOR_PID");
1043
1040
  if (override) {
1044
1041
  const n = Number(override);
1045
1042
  if (Number.isFinite(n) && n > 0)
1046
1043
  return n;
1047
1044
  }
1045
+ // A adapter that states its own pid ends the search. Nothing inferred from the
1046
+ // process tree beats the adapter naming itself, and the inference is the part
1047
+ // that has been failing: comm matching wants a binary called after its
1048
+ // adapter, and one Claude Code build ships its CLI under a version-numbered
1049
+ // filename, so the walk found nothing and the caller fell back to the hook's
1050
+ // own shell. That row was dead within seconds, leaving every session in this
1051
+ // environment unattributed.
1052
+ const fromEnv = adapterPidFromEnv();
1053
+ if (fromEnv)
1054
+ return fromEnv;
1048
1055
  // Build the ppid chain (nearest → root, up to 20 hops), then hand it to the
1049
1056
  // pure selector. Linux/WSL reads /proc; macOS/BSD (no /proc) falls back to
1050
1057
  // `ps -o ppid=,comm=` parsed by the unit-tested `parsePsChainLine`. Splitting
1051
- // the walk (untestable off a live box) from the comm-matching keeps the
1052
- // cursor `node`-fallback logic verifiable.
1058
+ // the walk (untestable off a live box) from the matching keeps the selector
1059
+ // logic verifiable.
1060
+ //
1061
+ // Only the /proc branch carries an executable path for the selector's
1062
+ // path-based pass. Asking `ps` for one means either a second spawn per hop or
1063
+ // splitting `comm` from `args` on a line where comm may itself contain spaces,
1064
+ // and the adapter that needs the path pass states its pid in the env anyway.
1053
1065
  const chain = [];
1054
1066
  let pid = process.pid;
1055
1067
  for (let hops = 0; hops < 20; hops++) {
@@ -1058,7 +1070,15 @@ function findHarnessAnchorPid(harness) {
1058
1070
  const comm = readFileSync(`/proc/${pid}/comm`, "utf8").trim();
1059
1071
  const status = readFileSync(`/proc/${pid}/status`, "utf8");
1060
1072
  const m = status.match(/^PPid:\s+(\d+)/m);
1061
- hop = { comm, ppid: m ? Number(m[1]) : 0 };
1073
+ // argv[0], for the path-based second pass. cmdline is NUL-separated.
1074
+ let exe;
1075
+ try {
1076
+ exe = readFileSync(`/proc/${pid}/cmdline`, "utf8").split("\0")[0] || undefined;
1077
+ }
1078
+ catch {
1079
+ /* exe is optional */
1080
+ }
1081
+ hop = { comm, ppid: m ? Number(m[1]) : 0, exe };
1062
1082
  }
1063
1083
  catch {
1064
1084
  // no /proc (macOS/BSD) — fall through to ps
@@ -1070,12 +1090,12 @@ function findHarnessAnchorPid(harness) {
1070
1090
  }
1071
1091
  if (!hop)
1072
1092
  break;
1073
- chain.push({ pid, comm: hop.comm });
1093
+ chain.push({ pid, comm: hop.comm, exe: hop.exe });
1074
1094
  if (!Number.isFinite(hop.ppid) || hop.ppid === 0 || hop.ppid === 1)
1075
1095
  break;
1076
1096
  pid = hop.ppid;
1077
1097
  }
1078
- return selectAnchorPid(chain, harness);
1098
+ return selectAnchorPid(chain, adapter);
1079
1099
  }
1080
1100
  /**
1081
1101
  * Pid-map self-heal for `tool.pre_use`. Symmetric counterpart to
@@ -1084,7 +1104,7 @@ function findHarnessAnchorPid(harness) {
1084
1104
  *
1085
1105
  * The pid argument prefers the payload's `pid` (CC populates it on
1086
1106
  * SessionStart and may also send it on PreToolUse), then
1087
- * `findHarnessAnchorPid`, then `process.ppid`. Writes go through the same
1107
+ * `findAdapterAnchorPid`, then `process.ppid`. Writes go through the same
1088
1108
  * idempotent `writePidmapViaAgentCoord` helper that SessionStart uses: no
1089
1109
  * disk I/O on no-op heals (when the row already points at us).
1090
1110
  *
@@ -1092,14 +1112,14 @@ function findHarnessAnchorPid(harness) {
1092
1112
  * `harn agents heal-events` pidmap counts meaningful. The inline helper does
1093
1113
  * not yet.
1094
1114
  */
1095
- function refreshPidmap(coordRoot, instanceId, harness, payloadPid) {
1096
- const pid = payloadPid ?? findHarnessAnchorPid(harness) ?? process.ppid;
1115
+ function refreshPidmap(coordRoot, instanceId, adapter, payloadPid) {
1116
+ const pid = payloadPid ?? findAdapterAnchorPid(adapter) ?? process.ppid;
1097
1117
  if (!Number.isFinite(pid) || pid <= 0)
1098
1118
  return;
1099
- writePidmapViaAgentCoord(coordRoot, pid, instanceId, harnessPlatform(harness));
1119
+ writePidmapViaAgentCoord(coordRoot, pid, instanceId, adapterPlatform(adapter));
1100
1120
  }
1101
1121
  function stampToolActivity(coordRoot, instanceId, data) {
1102
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1122
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1103
1123
  if (!existsSync(agentCoordBin))
1104
1124
  return;
1105
1125
  const toolName = data.tool_name ?? "";
@@ -1169,7 +1189,7 @@ function releaseClaimOnFailure(coordRoot, instanceId, data, rawPayload) {
1169
1189
  ? filePath.slice(coordRoot.length + 1)
1170
1190
  : filePath;
1171
1191
  }
1172
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1192
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1173
1193
  if (!existsSync(agentCoordBin))
1174
1194
  return;
1175
1195
  spawnSync(agentCoordBin, ["release-claim", instanceId, canonical], {
@@ -1213,13 +1233,13 @@ function cleanupSessionEnd(coordRoot, instanceId, reason) {
1213
1233
  }
1214
1234
  }
1215
1235
  // Activity log
1216
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1236
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1217
1237
  if (existsSync(agentCoordBin)) {
1218
1238
  spawnSync(agentCoordBin, ["log", `SESSION_END reason=${reason}`, "--instance", instanceId], { encoding: "utf8", timeout: 2000 });
1219
1239
  }
1220
1240
  }
1221
- async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionId, harness, recoveryBriefing = "") {
1222
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1241
+ async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionId, adapter, recoveryBriefing = "") {
1242
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1223
1243
  let additionalContext = "";
1224
1244
  if (existsSync(agentCoordBin)) {
1225
1245
  // Look up the agent's name from its heartbeat (for council pending rendering).
@@ -1238,11 +1258,16 @@ async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionI
1238
1258
  const args = ["prompt-context", "--instance", instanceId, "--session", sessionId];
1239
1259
  if (agentName)
1240
1260
  args.push("--name", agentName);
1241
- // Cursor + Codex sessions get the set-task staleness nudge. CC enforces it
1242
- // via the Stop-hook transcript scan; the nudge replaces that for harnesses
1243
- // that don't reliably expose a transcript_path during stop.
1244
- if (harness === "cursor" || harness === "codex")
1261
+ // Every human-facing adapter gets the first-session naming reminder from
1262
+ // the shared hook path. Cursor + Codex additionally get ongoing set-task
1263
+ // staleness nudges; Claude Code enforces those via its Stop transcript.
1264
+ // Codex gets a fresh status-footer reminder on every prompt. Its Stop hook
1265
+ // stays observe-only, so missing the footer never replaces the answer.
1266
+ args.push("--session-name-nudge");
1267
+ if (adapter === "cursor" || adapter === "codex")
1245
1268
  args.push("--task-nudge");
1269
+ if (adapter === "codex")
1270
+ args.push("--status-footer-nudge");
1246
1271
  const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
1247
1272
  if (result.status === 0 && result.stdout)
1248
1273
  additionalContext = result.stdout.trim();
@@ -1252,24 +1277,24 @@ async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionI
1252
1277
  }
1253
1278
  if (!additionalContext)
1254
1279
  return false;
1255
- const { emitContext } = await import("./harness/output.js");
1256
- emitContext(harness, "UserPromptSubmit", additionalContext);
1280
+ const { emitContext } = await import("./adapter/output.js");
1281
+ emitContext(adapter, "UserPromptSubmit", additionalContext);
1257
1282
  return true;
1258
1283
  }
1259
- function emitSubagentStartContext(coordRoot, instanceId, sessionId, data, harness) {
1284
+ function emitSubagentStartContext(coordRoot, instanceId, sessionId, data, adapter) {
1260
1285
  // Look up the subagent's assigned name (just-written by agent-coord assignName
1261
1286
  // in session.start data) + the parent's short id for the "you are a subagent
1262
1287
  // of X" framing.
1263
1288
  const subagentName = data.name ?? "";
1264
1289
  if (!subagentName)
1265
1290
  return;
1266
- const platformLabel = harnessPlatform(harness);
1291
+ const platformLabel = adapterPlatform(adapter);
1267
1292
  const parentShort = sessionId && sessionId !== instanceId ? `agent-${sessionId.slice(0, 8)}` : "the parent session";
1268
1293
  const message = `You are agent-${subagentName} (${platformLabel} subagent). You're a subagent of ${parentShort}.`;
1269
1294
  // Render peer table inline since the subagent might want to know who else
1270
1295
  // is around. Reuse prompt-context (which dedups against the per-owner hash);
1271
1296
  // first call will always emit.
1272
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1297
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1273
1298
  let combined = message;
1274
1299
  if (existsSync(agentCoordBin)) {
1275
1300
  const result = spawnSync(agentCoordBin, ["prompt-context", "--instance", instanceId, "--session", sessionId, "--name", subagentName], { encoding: "utf8", timeout: 3000 });
@@ -1279,17 +1304,17 @@ function emitSubagentStartContext(coordRoot, instanceId, sessionId, data, harnes
1279
1304
  }
1280
1305
  // Use SubagentStart event-name in CC's hookSpecificOutput shape; cursor's
1281
1306
  // flat `additional_context` works the same way.
1282
- void import("./harness/output.js").then(({ emitContext }) => {
1283
- emitContext(harness, "SubagentStart", combined);
1307
+ void import("./adapter/output.js").then(({ emitContext }) => {
1308
+ emitContext(adapter, "SubagentStart", combined);
1284
1309
  });
1285
1310
  }
1286
- function harnessPlatform(harness) {
1287
- if (harness === "claude-code")
1311
+ function adapterPlatform(adapter) {
1312
+ if (adapter === "claude-code")
1288
1313
  return "claude_code";
1289
- return harness;
1314
+ return adapter;
1290
1315
  }
1291
- async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, emittedData, harness, recoveryBriefing = "") {
1292
- const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
1316
+ async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, emittedData, adapter, recoveryBriefing = "") {
1317
+ const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1293
1318
  let additionalContext = "";
1294
1319
  if (existsSync(agentCoordBin)) {
1295
1320
  // Sync-project so the heartbeat exists for downstream readers (peer table,
@@ -1297,10 +1322,10 @@ async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, e
1297
1322
  spawnSync(agentCoordBin, ["project"], { encoding: "utf8", timeout: 3000 });
1298
1323
  // Stale-sweep dead peers before rendering peer table.
1299
1324
  spawnSync(agentCoordBin, ["stale-sweep"], { encoding: "utf8", timeout: 3000 });
1300
- // SESSION_START activity log line, fired across all harnesses.
1325
+ // SESSION_START activity log line, fired across all adapters.
1301
1326
  const model = emittedData.model ?? "unknown";
1302
1327
  const source = emittedData.source ?? "startup";
1303
- const platform = harnessPlatform(harness);
1328
+ const platform = adapterPlatform(adapter);
1304
1329
  spawnSync(agentCoordBin, [
1305
1330
  "log",
1306
1331
  `SESSION_START model=${model} source=${source} platform=${platform}`,
@@ -1315,19 +1340,19 @@ async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, e
1315
1340
  // The "You are agent-X." prefix in session-context renders unqualified by
1316
1341
  // default (claude-code-style). For cursor/codex the bash dispatchers add
1317
1342
  // a "(Cursor)" / "(Codex)" suffix; pass it through as --platform-label.
1318
- if (harness !== "claude-code") {
1343
+ if (adapter !== "claude-code") {
1319
1344
  args.push("--platform-label", platform === "cursor" ? "Cursor" : "Codex");
1320
1345
  }
1321
1346
  const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
1322
1347
  if (result.status === 0 && result.stdout)
1323
1348
  additionalContext = result.stdout.trim();
1324
1349
  }
1325
- // Effect (claude-code): merge the scratch recovery cue into the session-start
1350
+ // Effect (claude-code): merge the journal recovery cue into the session-start
1326
1351
  // context. Was a standalone additionalContext emission from the previous
1327
- // scratch-on-start adapter; now that agent-hook is the single SessionStart
1352
+ // journal-on-start adapter; now that agent-hook is the single SessionStart
1328
1353
  // entry, it folds in here.
1329
- if (harness === "claude-code") {
1330
- const cue = scratchRecoveryCue(coordRoot);
1354
+ if (adapter === "claude-code") {
1355
+ const cue = journalRecoveryCue(coordRoot);
1331
1356
  if (cue)
1332
1357
  additionalContext = [additionalContext, cue].filter(Boolean).join("\n\n");
1333
1358
  }
@@ -1336,17 +1361,17 @@ async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, e
1336
1361
  }
1337
1362
  if (!additionalContext)
1338
1363
  return false;
1339
- const { emitContext } = await import("./harness/output.js");
1340
- emitContext(harness, "SessionStart", additionalContext);
1364
+ const { emitContext } = await import("./adapter/output.js");
1365
+ emitContext(adapter, "SessionStart", additionalContext);
1341
1366
  return true;
1342
1367
  }
1343
- function completeRecoveryInjection(coordRoot, instanceId, sessionId, harness, recovery, injectionEvent) {
1368
+ function completeRecoveryInjection(coordRoot, instanceId, sessionId, adapter, recovery, injectionEvent) {
1344
1369
  completeContextRecovery(coordRoot, { sessionId, instanceId });
1345
1370
  emit(coordRoot, {
1346
1371
  event_type: "context.recovery.injected",
1347
1372
  instance_id: instanceId,
1348
1373
  session_id: sessionId,
1349
- harness,
1374
+ adapter,
1350
1375
  data: {
1351
1376
  capsule_id: recovery.capsule.capsule_id,
1352
1377
  generation: recovery.capsule.generation,