harnery 0.36.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/dist/commander.js +4 -0
  2. package/dist/commands/agents.d.ts.map +1 -1
  3. package/dist/commands/agents.js +87 -46
  4. package/dist/commands/artifacts.d.ts.map +1 -1
  5. package/dist/commands/artifacts.js +26 -1
  6. package/dist/commands/browse.d.ts.map +1 -1
  7. package/dist/commands/browse.js +11 -0
  8. package/dist/commands/diagnostics.d.ts +4 -0
  9. package/dist/commands/diagnostics.d.ts.map +1 -0
  10. package/dist/commands/diagnostics.js +229 -0
  11. package/dist/commands/files.d.ts +12 -0
  12. package/dist/commands/files.d.ts.map +1 -1
  13. package/dist/commands/files.js +54 -1
  14. package/dist/commands/governor.d.ts.map +1 -1
  15. package/dist/commands/governor.js +4 -0
  16. package/dist/commands/ledger-v3.d.ts.map +1 -1
  17. package/dist/commands/ledger-v3.js +71 -2
  18. package/dist/commands/qa-run.d.ts +4 -0
  19. package/dist/commands/qa-run.d.ts.map +1 -0
  20. package/dist/commands/qa-run.js +141 -0
  21. package/dist/commands/resources.d.ts +4 -0
  22. package/dist/commands/resources.d.ts.map +1 -0
  23. package/dist/commands/resources.js +29 -0
  24. package/dist/commands/supervisor.d.ts +4 -0
  25. package/dist/commands/supervisor.d.ts.map +1 -0
  26. package/dist/commands/supervisor.js +101 -0
  27. package/dist/commands/web.d.ts.map +1 -1
  28. package/dist/commands/web.js +17 -0
  29. package/dist/commands/workflow.d.ts.map +1 -1
  30. package/dist/commands/workflow.js +4 -0
  31. package/dist/core/agents/cli.js +7 -3
  32. package/dist/core/agents/health.d.ts +17 -0
  33. package/dist/core/agents/health.d.ts.map +1 -0
  34. package/dist/core/agents/health.js +109 -0
  35. package/dist/core/agents/mailbox.d.ts +92 -0
  36. package/dist/core/agents/mailbox.d.ts.map +1 -0
  37. package/dist/core/agents/mailbox.js +325 -0
  38. package/dist/core/agents/reconcile-coordination-v3.d.ts +44 -0
  39. package/dist/core/agents/reconcile-coordination-v3.d.ts.map +1 -0
  40. package/dist/core/agents/reconcile-coordination-v3.js +58 -0
  41. package/dist/core/agents/render/prompt-context.d.ts +5 -0
  42. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  43. package/dist/core/agents/render/prompt-context.js +34 -13
  44. package/dist/core/agents/render/session-context.d.ts +8 -0
  45. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  46. package/dist/core/agents/render/session-context.js +34 -3
  47. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  48. package/dist/core/agents/rules/commit-conflict.js +50 -1
  49. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  50. package/dist/core/agents/rules/stop-hook.js +6 -10
  51. package/dist/core/agents/session-finalizer-v3.js +4 -1
  52. package/dist/core/artifacts/index.d.ts +26 -1
  53. package/dist/core/artifacts/index.d.ts.map +1 -1
  54. package/dist/core/artifacts/index.js +146 -6
  55. package/dist/core/config.d.ts +12 -0
  56. package/dist/core/config.d.ts.map +1 -1
  57. package/dist/core/config.js +43 -0
  58. package/dist/core/diagnostics/advice.d.ts +9 -0
  59. package/dist/core/diagnostics/advice.d.ts.map +1 -0
  60. package/dist/core/diagnostics/advice.js +112 -0
  61. package/dist/core/diagnostics/bundle.d.ts +35 -0
  62. package/dist/core/diagnostics/bundle.d.ts.map +1 -0
  63. package/dist/core/diagnostics/bundle.js +874 -0
  64. package/dist/core/diagnostics/comparison.d.ts +5 -0
  65. package/dist/core/diagnostics/comparison.d.ts.map +1 -0
  66. package/dist/core/diagnostics/comparison.js +444 -0
  67. package/dist/core/diagnostics/contract.d.ts +245 -0
  68. package/dist/core/diagnostics/contract.d.ts.map +1 -0
  69. package/dist/core/diagnostics/contract.js +18 -0
  70. package/dist/core/diagnostics/identity.d.ts +3 -0
  71. package/dist/core/diagnostics/identity.d.ts.map +1 -0
  72. package/dist/core/diagnostics/identity.js +10 -0
  73. package/dist/core/diagnostics/index.d.ts +8 -0
  74. package/dist/core/diagnostics/index.d.ts.map +1 -0
  75. package/dist/core/diagnostics/index.js +7 -0
  76. package/dist/core/diagnostics/replay.d.ts +8 -0
  77. package/dist/core/diagnostics/replay.d.ts.map +1 -0
  78. package/dist/core/diagnostics/replay.js +213 -0
  79. package/dist/core/diagnostics/sanitize.d.ts +9 -0
  80. package/dist/core/diagnostics/sanitize.d.ts.map +1 -0
  81. package/dist/core/diagnostics/sanitize.js +84 -0
  82. package/dist/core/events/legacy-storage/compression.d.ts +13 -0
  83. package/dist/core/events/legacy-storage/compression.d.ts.map +1 -0
  84. package/dist/core/events/legacy-storage/compression.js +107 -0
  85. package/dist/core/events/legacy-storage/index.d.ts +1 -0
  86. package/dist/core/events/legacy-storage/index.d.ts.map +1 -1
  87. package/dist/core/events/legacy-storage/index.js +1 -0
  88. package/dist/core/events/v3/archive-retention.d.ts +33 -0
  89. package/dist/core/events/v3/archive-retention.d.ts.map +1 -0
  90. package/dist/core/events/v3/archive-retention.js +195 -0
  91. package/dist/core/events/v3/capabilities.d.ts +1 -1
  92. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  93. package/dist/core/events/v3/capabilities.js +1 -0
  94. package/dist/core/events/v3/index.d.ts +1 -0
  95. package/dist/core/events/v3/index.d.ts.map +1 -1
  96. package/dist/core/events/v3/index.js +1 -0
  97. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  98. package/dist/core/events/v3/live-routing.js +1 -0
  99. package/dist/core/events/v3/producers/hook-base.d.ts +1 -1
  100. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  101. package/dist/core/events/v3/producers/hook-base.js +13 -2
  102. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  103. package/dist/core/events/v3/producers/intake.js +1 -0
  104. package/dist/core/events/v3/producers/recorder.d.ts +16 -0
  105. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  106. package/dist/core/events/v3/producers/recorder.js +88 -1
  107. package/dist/core/hooks/adapter/output.d.ts +8 -0
  108. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  109. package/dist/core/hooks/adapter/output.js +11 -1
  110. package/dist/core/hooks/cli.js +183 -192
  111. package/dist/core/hooks/health.d.ts +59 -0
  112. package/dist/core/hooks/health.d.ts.map +1 -0
  113. package/dist/core/hooks/health.js +84 -0
  114. package/dist/core/resources/contract.d.ts +90 -0
  115. package/dist/core/resources/contract.d.ts.map +1 -0
  116. package/dist/core/resources/contract.js +2 -0
  117. package/dist/core/resources/index.d.ts +6 -0
  118. package/dist/core/resources/index.d.ts.map +1 -0
  119. package/dist/core/resources/index.js +5 -0
  120. package/dist/core/resources/sampler.d.ts +27 -0
  121. package/dist/core/resources/sampler.d.ts.map +1 -0
  122. package/dist/core/resources/sampler.js +357 -0
  123. package/dist/core/resources/service-status.d.ts +3 -0
  124. package/dist/core/resources/service-status.d.ts.map +1 -0
  125. package/dist/core/resources/service-status.js +48 -0
  126. package/dist/core/resources/service.d.ts +26 -0
  127. package/dist/core/resources/service.d.ts.map +1 -0
  128. package/dist/core/resources/service.js +292 -0
  129. package/dist/core/resources/storage.d.ts +13 -0
  130. package/dist/core/resources/storage.d.ts.map +1 -0
  131. package/dist/core/resources/storage.js +30 -0
  132. package/dist/core/storage/atomic-json.d.ts +3 -0
  133. package/dist/core/storage/atomic-json.d.ts.map +1 -0
  134. package/dist/core/storage/atomic-json.js +15 -0
  135. package/dist/core/storage/builtins.d.ts.map +1 -1
  136. package/dist/core/storage/builtins.js +45 -6
  137. package/dist/core/storage/logger.d.ts +2 -0
  138. package/dist/core/storage/logger.d.ts.map +1 -1
  139. package/dist/core/storage/logger.js +2 -0
  140. package/dist/core/storage/query.d.ts +14 -0
  141. package/dist/core/storage/query.d.ts.map +1 -1
  142. package/dist/core/storage/query.js +51 -0
  143. package/dist/core/supervisor/activity.d.ts +4 -0
  144. package/dist/core/supervisor/activity.d.ts.map +1 -0
  145. package/dist/core/supervisor/activity.js +141 -0
  146. package/dist/core/supervisor/contract.d.ts +268 -0
  147. package/dist/core/supervisor/contract.d.ts.map +1 -0
  148. package/dist/core/supervisor/contract.js +35 -0
  149. package/dist/core/supervisor/explanations.d.ts +4 -0
  150. package/dist/core/supervisor/explanations.d.ts.map +1 -0
  151. package/dist/core/supervisor/explanations.js +71 -0
  152. package/dist/core/supervisor/findings.d.ts +20 -0
  153. package/dist/core/supervisor/findings.d.ts.map +1 -0
  154. package/dist/core/supervisor/findings.js +399 -0
  155. package/dist/core/supervisor/history.d.ts +9 -0
  156. package/dist/core/supervisor/history.d.ts.map +1 -0
  157. package/dist/core/supervisor/history.js +46 -0
  158. package/dist/core/supervisor/hook-health-alerts.d.ts +14 -0
  159. package/dist/core/supervisor/hook-health-alerts.d.ts.map +1 -0
  160. package/dist/core/supervisor/hook-health-alerts.js +70 -0
  161. package/dist/core/supervisor/hook-health-storage.d.ts +5 -0
  162. package/dist/core/supervisor/hook-health-storage.d.ts.map +1 -0
  163. package/dist/core/supervisor/hook-health-storage.js +24 -0
  164. package/dist/core/supervisor/hook-health.d.ts +72 -0
  165. package/dist/core/supervisor/hook-health.d.ts.map +1 -0
  166. package/dist/core/supervisor/hook-health.js +203 -0
  167. package/dist/core/supervisor/hooks.d.ts +10 -0
  168. package/dist/core/supervisor/hooks.d.ts.map +1 -0
  169. package/dist/core/supervisor/hooks.js +28 -0
  170. package/dist/core/supervisor/index.d.ts +15 -0
  171. package/dist/core/supervisor/index.d.ts.map +1 -0
  172. package/dist/core/supervisor/index.js +14 -0
  173. package/dist/core/supervisor/log-feed.d.ts +9 -0
  174. package/dist/core/supervisor/log-feed.d.ts.map +1 -0
  175. package/dist/core/supervisor/log-feed.js +103 -0
  176. package/dist/core/supervisor/service.d.ts +29 -0
  177. package/dist/core/supervisor/service.d.ts.map +1 -0
  178. package/dist/core/supervisor/service.js +450 -0
  179. package/dist/core/supervisor/services.d.ts +11 -0
  180. package/dist/core/supervisor/services.d.ts.map +1 -0
  181. package/dist/core/supervisor/services.js +155 -0
  182. package/dist/core/supervisor/status.d.ts +3 -0
  183. package/dist/core/supervisor/status.d.ts.map +1 -0
  184. package/dist/core/supervisor/status.js +48 -0
  185. package/dist/core/supervisor/storage.d.ts +30 -0
  186. package/dist/core/supervisor/storage.d.ts.map +1 -0
  187. package/dist/core/supervisor/storage.js +73 -0
  188. package/dist/core/supervisor/timeline.d.ts +3 -0
  189. package/dist/core/supervisor/timeline.d.ts.map +1 -0
  190. package/dist/core/supervisor/timeline.js +87 -0
  191. package/dist/core/workflow/admission.d.ts +23 -0
  192. package/dist/core/workflow/admission.d.ts.map +1 -0
  193. package/dist/core/workflow/admission.js +136 -0
  194. package/dist/core/workflow/engine.d.ts.map +1 -1
  195. package/dist/core/workflow/engine.js +77 -2
  196. package/dist/core/workflow/index.d.ts +3 -2
  197. package/dist/core/workflow/index.d.ts.map +1 -1
  198. package/dist/core/workflow/index.js +2 -1
  199. package/dist/core/workflow/proof.d.ts +2 -1
  200. package/dist/core/workflow/proof.d.ts.map +1 -1
  201. package/dist/core/workflow/proof.js +39 -1
  202. package/dist/core/workflow/run-state.d.ts +3 -2
  203. package/dist/core/workflow/run-state.d.ts.map +1 -1
  204. package/dist/core/workflow/run-state.js +8 -1
  205. package/dist/core/workflow/types.d.ts +33 -1
  206. package/dist/core/workflow/types.d.ts.map +1 -1
  207. package/dist/core/workflow/types.js +2 -1
  208. package/dist/lib/browser/client.d.ts +5 -0
  209. package/dist/lib/browser/client.d.ts.map +1 -1
  210. package/dist/lib/browser/client.js +1 -0
  211. package/dist/lib/browser/index.d.ts +2 -0
  212. package/dist/lib/browser/index.d.ts.map +1 -1
  213. package/dist/lib/browser/index.js +2 -0
  214. package/dist/lib/browser/qa-run-contracts.d.ts +173 -0
  215. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -0
  216. package/dist/lib/browser/qa-run-contracts.js +226 -0
  217. package/dist/lib/browser/qa-run.d.ts +51 -0
  218. package/dist/lib/browser/qa-run.d.ts.map +1 -0
  219. package/dist/lib/browser/qa-run.js +684 -0
  220. package/dist/lib/coord-root-id.d.ts +9 -0
  221. package/dist/lib/coord-root-id.d.ts.map +1 -0
  222. package/dist/lib/coord-root-id.js +17 -0
  223. package/dist/lib/instructions/apply.d.ts +3 -1
  224. package/dist/lib/instructions/apply.d.ts.map +1 -1
  225. package/dist/lib/instructions/apply.js +74 -3
  226. package/dist/lib/instructions/templates.d.ts.map +1 -1
  227. package/dist/lib/instructions/templates.js +6 -0
  228. package/package.json +12 -1
  229. package/src/commander.ts +26 -0
  230. package/src/commands/agents.ts +102 -49
  231. package/src/commands/artifacts.ts +40 -2
  232. package/src/commands/browse.ts +15 -0
  233. package/src/commands/diagnostics.ts +271 -0
  234. package/src/commands/files.ts +102 -2
  235. package/src/commands/governor.ts +8 -0
  236. package/src/commands/ledger-v3.ts +82 -0
  237. package/src/commands/qa-run.ts +184 -0
  238. package/src/commands/resources.ts +38 -0
  239. package/src/commands/supervisor.ts +141 -0
  240. package/src/commands/web.ts +19 -0
  241. package/src/commands/workflow.ts +8 -0
  242. package/src/core/agents/cli.ts +7 -3
  243. package/src/core/agents/health.ts +142 -0
  244. package/src/core/agents/mailbox.ts +373 -0
  245. package/src/core/agents/reconcile-coordination-v3.ts +77 -0
  246. package/src/core/agents/render/prompt-context.ts +42 -12
  247. package/src/core/agents/render/session-context.ts +37 -3
  248. package/src/core/agents/rules/commit-conflict.ts +58 -1
  249. package/src/core/agents/rules/stop-hook.ts +6 -12
  250. package/src/core/agents/session-finalizer-v3.ts +4 -1
  251. package/src/core/artifacts/index.ts +196 -10
  252. package/src/core/config.ts +111 -2
  253. package/src/core/diagnostics/advice.ts +147 -0
  254. package/src/core/diagnostics/bundle.ts +1142 -0
  255. package/src/core/diagnostics/comparison.ts +565 -0
  256. package/src/core/diagnostics/contract.ts +311 -0
  257. package/src/core/diagnostics/identity.ts +11 -0
  258. package/src/core/diagnostics/index.ts +7 -0
  259. package/src/core/diagnostics/replay.ts +314 -0
  260. package/src/core/diagnostics/sanitize.ts +97 -0
  261. package/src/core/events/legacy-storage/compression.ts +130 -0
  262. package/src/core/events/legacy-storage/index.ts +1 -0
  263. package/src/core/events/v3/archive-retention.ts +251 -0
  264. package/src/core/events/v3/capabilities.ts +2 -0
  265. package/src/core/events/v3/index.ts +9 -0
  266. package/src/core/events/v3/live-routing.ts +1 -0
  267. package/src/core/events/v3/producers/hook-base.ts +14 -2
  268. package/src/core/events/v3/producers/intake.ts +1 -0
  269. package/src/core/events/v3/producers/recorder.ts +110 -1
  270. package/src/core/hooks/adapter/output.ts +12 -1
  271. package/src/core/hooks/cli.ts +192 -215
  272. package/src/core/hooks/health.ts +146 -0
  273. package/src/core/resources/contract.ts +98 -0
  274. package/src/core/resources/index.ts +5 -0
  275. package/src/core/resources/sampler.ts +458 -0
  276. package/src/core/resources/service-status.ts +62 -0
  277. package/src/core/resources/service.ts +337 -0
  278. package/src/core/resources/storage.ts +44 -0
  279. package/src/core/storage/atomic-json.ts +15 -0
  280. package/src/core/storage/builtins.ts +62 -6
  281. package/src/core/storage/logger.ts +2 -0
  282. package/src/core/storage/query.ts +58 -0
  283. package/src/core/supervisor/activity.ts +193 -0
  284. package/src/core/supervisor/contract.ts +312 -0
  285. package/src/core/supervisor/explanations.ts +104 -0
  286. package/src/core/supervisor/findings.ts +788 -0
  287. package/src/core/supervisor/history.ts +61 -0
  288. package/src/core/supervisor/hook-health-alerts.ts +108 -0
  289. package/src/core/supervisor/hook-health-storage.ts +25 -0
  290. package/src/core/supervisor/hook-health.ts +301 -0
  291. package/src/core/supervisor/hooks.ts +35 -0
  292. package/src/core/supervisor/index.ts +14 -0
  293. package/src/core/supervisor/log-feed.ts +131 -0
  294. package/src/core/supervisor/service.ts +511 -0
  295. package/src/core/supervisor/services.ts +203 -0
  296. package/src/core/supervisor/status.ts +59 -0
  297. package/src/core/supervisor/storage.ts +126 -0
  298. package/src/core/supervisor/timeline.ts +133 -0
  299. package/src/core/workflow/admission.ts +215 -0
  300. package/src/core/workflow/engine.ts +93 -1
  301. package/src/core/workflow/index.ts +10 -0
  302. package/src/core/workflow/proof.ts +54 -1
  303. package/src/core/workflow/run-state.ts +13 -1
  304. package/src/core/workflow/types.ts +39 -1
  305. package/src/lib/browser/client.ts +6 -0
  306. package/src/lib/browser/index.ts +29 -0
  307. package/src/lib/browser/qa-run-contracts.ts +380 -0
  308. package/src/lib/browser/qa-run.ts +784 -0
  309. package/src/lib/coord-root-id.ts +23 -0
  310. package/src/lib/instructions/apply.ts +81 -2
  311. package/src/lib/instructions/templates.ts +6 -0
@@ -0,0 +1,23 @@
1
+ import { createHash } from "node:crypto";
2
+ import { realpathSync } from "node:fs";
3
+ import { DEFAULT_WEB_PORT } from "./local-file-url.ts";
4
+
5
+ /** Local-only endpoint used to prove that a dashboard serves the caller's repo. */
6
+ export const COORD_ROOT_ID_PATH = "/api/coord-root";
7
+
8
+ /**
9
+ * Opaque identity for a canonical coordination root. The path stays local;
10
+ * only its digest crosses the dashboard boundary.
11
+ */
12
+ export function coordRootId(root: string): string {
13
+ const canonical = realpathSync(root);
14
+ return `sha256:${createHash("sha256").update(canonical).digest("hex")}`;
15
+ }
16
+
17
+ export function localCoordRootIdUrl(
18
+ port: number | string = DEFAULT_WEB_PORT,
19
+ protocol = "http:",
20
+ ): string {
21
+ const portPart = String(port) === "" ? "" : `:${port}`;
22
+ return `${protocol}//127.0.0.1${portPart}${COORD_ROOT_ID_PATH}`;
23
+ }
@@ -7,13 +7,15 @@
7
7
  * writes, and deletes so init/deinit stay thin and this stays integration-
8
8
  * testable against a temp dir.
9
9
  *
10
- * Two files, one dir:
10
+ * Three files, one dir:
11
11
  * - `AGENTS.md` — the always-on orientation block (a managed region; the
12
12
  * consumer owns the rest of the file).
13
13
  * - `CLAUDE.md` — claude-code only; Claude Code reads CLAUDE.md, not AGENTS.md,
14
14
  * so a fresh consumer gets a CLAUDE.md whose managed region imports
15
15
  * `@AGENTS.md`. A CLAUDE.md that already imports AGENTS.md or already carries
16
16
  * the block (a host that generates CLAUDE.md from AGENTS.md) is left alone.
17
+ * - `.cursor/rules/harnery-turn-ritual.mdc` — cursor only; an Always Apply
18
+ * rule that makes the Stop-enforced status footer visible in reply text.
17
19
  * - `<adapter-skill-dir>/<skill>/SKILL.md` — fully-owned files, honoring
18
20
  * `skills.exclude` in `.harnery/config.jsonc`. Claude Code uses
19
21
  * `.claude/skills/`; Cursor and Codex use `.agents/skills/`.
@@ -29,7 +31,7 @@ import {
29
31
  writeFileSync,
30
32
  } from "node:fs";
31
33
  import { dirname, join } from "node:path";
32
- import { stripJsonComments } from "../../core/config.ts";
34
+ import { endOfTurnStatusCommand, stripJsonComments } from "../../core/config.ts";
33
35
  import { readHostAddendum } from "./host-addendum.ts";
34
36
  import {
35
37
  checkOwnedSkill,
@@ -37,6 +39,7 @@ import {
37
39
  isOwnedFile,
38
40
  type ManagedStatus,
39
41
  removeRegion,
42
+ shortHash,
40
43
  spliceRegion,
41
44
  } from "./splice.ts";
42
45
  import {
@@ -50,6 +53,7 @@ import {
50
53
 
51
54
  const AGENTS_FILE = "AGENTS.md";
52
55
  const CLAUDE_FILE = "CLAUDE.md";
56
+ const CURSOR_RULE_FILE = join(".cursor", "rules", "harnery-turn-ritual.mdc");
53
57
  const ADAPTER_SKILLS_DIR: Readonly<Record<string, string>> = {
54
58
  "claude-code": join(".claude", "skills"),
55
59
  cursor: join(".agents", "skills"),
@@ -71,6 +75,39 @@ function skillBody(render: (bin: string) => string, binName: string): string {
71
75
  return content.slice(content.indexOf("-->") + 3).trim();
72
76
  }
73
77
 
78
+ function cursorRuleBody(projectRoot: string, binName: string): string {
79
+ const statusCommand = endOfTurnStatusCommand(projectRoot);
80
+ return [
81
+ "# Harnery turn ritual",
82
+ "",
83
+ "On every turn that uses tools:",
84
+ "",
85
+ `1. Run \`${binName} agents set-task "<short focus>"\` during the turn, even when the focus is unchanged.`,
86
+ `2. Make \`${statusCommand}\` your final tool call.`,
87
+ "3. Append that command's stdout verbatim in a fenced code block at the bottom of the same substantive reply.",
88
+ "",
89
+ "Cursor Stop enforces all three signals. A missing signal produces one follow-up that names every repair needed.",
90
+ ].join("\n");
91
+ }
92
+
93
+ function cursorRuleContent(projectRoot: string, binName: string): string {
94
+ const body = cursorRuleBody(projectRoot, binName);
95
+ const marker =
96
+ `<!-- harnery:generated cursor-turn-ritual v=${shortHash(body)}; machine-owned; ` +
97
+ `regenerated by \`${binName} init\`, removed by \`${binName} deinit\`. ` +
98
+ "Edit the harnery template, not this file. -->";
99
+ return [
100
+ "---",
101
+ "description: Harnery end-of-turn coordination ritual",
102
+ "alwaysApply: true",
103
+ "---",
104
+ marker,
105
+ "",
106
+ body,
107
+ "",
108
+ ].join("\n");
109
+ }
110
+
74
111
  /** Read `skills.exclude` from `.harnery/config.jsonc` (absent/unparseable → none). */
75
112
  export function readSkillsExclude(projectRoot: string): Set<string> {
76
113
  const p = join(projectRoot, ".harnery", "config.jsonc");
@@ -203,6 +240,27 @@ export function applyInstructions(projectRoot: string, opts: ApplyOpts): ApplyRe
203
240
  }
204
241
  }
205
242
 
243
+ // ── Cursor Always Apply rule ────────────────────────────────────────────
244
+ if (opts.adapter === "cursor") {
245
+ const rulePath = join(projectRoot, CURSOR_RULE_FILE);
246
+ const content = cursorRuleContent(projectRoot, opts.binName);
247
+ const before = existsSync(rulePath) ? readFileSync(rulePath, "utf8") : null;
248
+ if (before === content) {
249
+ actions.push(`· ${CURSOR_RULE_FILE} already current`);
250
+ } else if (before !== null && !isOwnedFile(before)) {
251
+ warnings.push(`left ${CURSOR_RULE_FILE} (hand-edited; no harnery ownership marker)`);
252
+ } else {
253
+ if (!opts.dryRun) {
254
+ mkdirSync(dirname(rulePath), { recursive: true });
255
+ writeFileSync(rulePath, content);
256
+ }
257
+ const fresh = before === null;
258
+ actions.push(
259
+ `${fresh ? "+" : "~"} ${verbed(fresh ? "write" : "update", fresh ? "wrote" : "updated")} ${CURSOR_RULE_FILE}`,
260
+ );
261
+ }
262
+ }
263
+
206
264
  // ── shipped skills ───────────────────────────────────────────────────────
207
265
  if (skillsDir) {
208
266
  const exclude = readSkillsExclude(projectRoot);
@@ -301,6 +359,18 @@ export function removeInstructions(projectRoot: string, opts: RemoveOpts): Apply
301
359
  }
302
360
  }
303
361
 
362
+ if (opts.adapter === "cursor") {
363
+ const rulePath = join(projectRoot, CURSOR_RULE_FILE);
364
+ if (existsSync(rulePath)) {
365
+ if (!isOwnedFile(readFileSync(rulePath, "utf8"))) {
366
+ warnings.push(`left ${CURSOR_RULE_FILE} (hand-edited; no harnery ownership marker)`);
367
+ } else {
368
+ if (!opts.dryRun) rmSync(rulePath);
369
+ actions.push(`+ ${opts.dryRun ? "would delete" : "deleted"} ${CURSOR_RULE_FILE}`);
370
+ }
371
+ }
372
+ }
373
+
304
374
  // ── shipped skills ───────────────────────────────────────────────────────
305
375
  if (skillsDir) {
306
376
  for (const skill of SKILLS) {
@@ -384,6 +454,15 @@ export function checkInstructions(
384
454
  note(`skill ${skill.id}`, checkOwnedSkill(c, skillBody(skill.render, opts.binName)));
385
455
  }
386
456
  }
457
+
458
+ if (opts.adapter === "cursor") {
459
+ const rulePath = join(projectRoot, CURSOR_RULE_FILE);
460
+ const content = existsSync(rulePath) ? readFileSync(rulePath, "utf8") : "";
461
+ note(
462
+ `${CURSOR_RULE_FILE} rule`,
463
+ checkOwnedSkill(content, cursorRuleBody(projectRoot, opts.binName)),
464
+ );
465
+ }
387
466
  } catch (err) {
388
467
  errored = true;
389
468
  issues.push(`error reading instructions state: ${(err as Error).message}`);
@@ -135,6 +135,12 @@ coordination ledger (\`.harnery/ledgers/v3/\`). Lead a shell command with a
135
135
  carries a reason instead of \`(no intent)\`; the [tool-intent
136
136
  guide](https://harnery.com/guides/tool-intent/) owns the details.
137
137
 
138
+ **Messaging another agent.** \`${b} agents ping <name> "<message>"\` reaches an
139
+ agent by name whether or not they are running: a live agent sees it on their next
140
+ prompt, and a dormant name holds it until a session of that name next starts.
141
+ Send it as your first and only step. Do not check who is live first, and do not
142
+ hunt for somewhere else to leave it. Only a never-used name is refused.
143
+
138
144
  **Journal.** \`${b} journal add <category> "<text>"\` (category = ${journalCats})
139
145
  leaves breadcrumbs that survive context compaction;
140
146
  \`${b} journal read\` reads yours, \`${b} journal read --name <peer>\` reads a peer's.