frayui 0.1.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 (173) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +186 -0
  3. package/dist/claude-agent-broker.js +21641 -0
  4. package/dist/codex-app-server-daemon.js +354 -0
  5. package/dist/dev-child.js +40319 -0
  6. package/dist/frayui.js +8738 -0
  7. package/package.json +46 -0
  8. package/runtime/cc/scripts/fray/agent-bindings.mjs +287 -0
  9. package/runtime/cc/scripts/fray/agent-liveness.mjs +367 -0
  10. package/runtime/cc/scripts/fray/agent-status.mjs +178 -0
  11. package/runtime/cc/scripts/fray/config.mjs +982 -0
  12. package/runtime/cc/scripts/fray/decisions.mjs +97 -0
  13. package/runtime/cc/scripts/fray/index.mjs +699 -0
  14. package/runtime/cc/scripts/fray/notify-shared.mjs +90 -0
  15. package/runtime/cc/scripts/fray/notify.mjs +81 -0
  16. package/runtime/cc/scripts/fray/ownership.mjs +120 -0
  17. package/runtime/cc/scripts/fray/rest-detect.mjs +213 -0
  18. package/runtime/cc/scripts/fray/thread-excerpt.mjs +162 -0
  19. package/runtime/cc/scripts/fray/thread-update.mjs +285 -0
  20. package/runtime/cc-worker/.claude-plugin/plugin.json +10 -0
  21. package/runtime/cc-worker/DECISIONS.md +923 -0
  22. package/runtime/cc-worker/LICENSE +21 -0
  23. package/runtime/cc-worker/agents/fable-high.md +8 -0
  24. package/runtime/cc-worker/agents/fable-low.md +8 -0
  25. package/runtime/cc-worker/agents/fable-max.md +8 -0
  26. package/runtime/cc-worker/agents/fable-medium.md +8 -0
  27. package/runtime/cc-worker/agents/fable-xhigh.md +8 -0
  28. package/runtime/cc-worker/agents/haiku.md +7 -0
  29. package/runtime/cc-worker/agents/opus-high.md +8 -0
  30. package/runtime/cc-worker/agents/opus-low.md +8 -0
  31. package/runtime/cc-worker/agents/opus-max.md +8 -0
  32. package/runtime/cc-worker/agents/opus-medium.md +8 -0
  33. package/runtime/cc-worker/agents/opus-xhigh.md +8 -0
  34. package/runtime/cc-worker/agents/sonnet-high.md +8 -0
  35. package/runtime/cc-worker/agents/sonnet-low.md +8 -0
  36. package/runtime/cc-worker/agents/sonnet-max.md +8 -0
  37. package/runtime/cc-worker/agents/sonnet-medium.md +8 -0
  38. package/runtime/cc-worker/agents/sonnet-xhigh.md +8 -0
  39. package/runtime/cc-worker/bin/fray +17 -0
  40. package/runtime/cc-worker/bin/fray-mcp.mjs +248 -0
  41. package/runtime/cc-worker/bin/fray-update +18 -0
  42. package/runtime/cc-worker/hooks/agent-bind.mjs +40 -0
  43. package/runtime/cc-worker/hooks/agent-dispatch.mjs +74 -0
  44. package/runtime/cc-worker/hooks/bash-background.d.mts +6 -0
  45. package/runtime/cc-worker/hooks/bash-background.mjs +188 -0
  46. package/runtime/cc-worker/hooks/deny-ask.mjs +38 -0
  47. package/runtime/cc-worker/hooks/deny-plan.mjs +61 -0
  48. package/runtime/cc-worker/hooks/hooks.json +111 -0
  49. package/runtime/cc-worker/hooks/perm-policy.mjs +211 -0
  50. package/runtime/cc-worker/hooks/precompact-instructions.mjs +122 -0
  51. package/runtime/cc-worker/hooks/scratchpad-stop.mjs +125 -0
  52. package/runtime/cc-worker/hooks/scratchpad.mjs +419 -0
  53. package/runtime/cc-worker/hooks/session-seed.mjs +105 -0
  54. package/runtime/cc-worker/scripts/fray/agent-bindings.mjs +9 -0
  55. package/runtime/cc-worker/scripts/fray/config.mjs +12 -0
  56. package/runtime/cc-worker/skills/gh/SKILL.md +132 -0
  57. package/runtime/cc-worker/skills/gh/scripts/ci-watch.mjs +60 -0
  58. package/runtime/cc-worker/skills/gh/scripts/github-watch.mjs +130 -0
  59. package/runtime/cc-worker/skills/gh/scripts/review-watch.mjs +54 -0
  60. package/runtime/cc-worker/skills/handoff/SKILL.md +203 -0
  61. package/runtime/cc-worker/skills/waits/SKILL.md +83 -0
  62. package/web-dist/apple-touch-icon.png +0 -0
  63. package/web-dist/assets/TerminalPane-fMGrgB-a.js +7 -0
  64. package/web-dist/assets/abnfDiagram-VRR7QNED-BtlrDuYX.js +1 -0
  65. package/web-dist/assets/arc-BSyeo0Gb.js +1 -0
  66. package/web-dist/assets/architecture-TIHT7OUA-CuD8jpr-.js +1 -0
  67. package/web-dist/assets/architectureDiagram-ZJ3FMSHR-CdLQ71be.js +36 -0
  68. package/web-dist/assets/array-BifhSqXX.js +1 -0
  69. package/web-dist/assets/blockDiagram-677ZJIJ3-CBk2FHEj.js +132 -0
  70. package/web-dist/assets/c4Diagram-LMCZKHZV-mZ3HQ6WX.js +10 -0
  71. package/web-dist/assets/channel-C2eUWc74.js +1 -0
  72. package/web-dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  73. package/web-dist/assets/chunk-32BRIVSS-Daxvi7f5.js +1 -0
  74. package/web-dist/assets/chunk-52WLFC77-BGJoZvry.js +10 -0
  75. package/web-dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  76. package/web-dist/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
  77. package/web-dist/assets/chunk-C7G6YPKG-Ycd1yheh.js +1 -0
  78. package/web-dist/assets/chunk-EX3LRPZG-BPFhlsHp.js +231 -0
  79. package/web-dist/assets/chunk-FWX5IMBZ--xy8DTon.js +2 -0
  80. package/web-dist/assets/chunk-HOUHSVGY-Dq3zoygp.js +1 -0
  81. package/web-dist/assets/chunk-ICXQ74PX-FfKP-7yM.js +2 -0
  82. package/web-dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  83. package/web-dist/assets/chunk-KEIR6QF5-BfrZ3jm6.js +161 -0
  84. package/web-dist/assets/chunk-MOJQB5TN-BeiHnsLF.js +88 -0
  85. package/web-dist/assets/chunk-OGEWGWER-CjDU_9fC.js +1 -0
  86. package/web-dist/assets/chunk-PUDLZKDR-BO7tm5QX.js +156 -0
  87. package/web-dist/assets/chunk-Q4XR5HBZ-BPefovOg.js +70 -0
  88. package/web-dist/assets/chunk-RYQCIY6F-Cu_KplZW.js +1 -0
  89. package/web-dist/assets/chunk-V7JOEXUC-DWnebFHh.js +206 -0
  90. package/web-dist/assets/chunk-VAUOI2AC-BL6qWFhW.js +1 -0
  91. package/web-dist/assets/chunk-VR4S4FIN-Mfs__7L9.js +1 -0
  92. package/web-dist/assets/chunk-WYO6CB5R-Bf2IYbEU.js +127 -0
  93. package/web-dist/assets/chunk-XXDRQBXY-DYlTP5J-.js +1 -0
  94. package/web-dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  95. package/web-dist/assets/chunk-ZGVPDNZ5-CJ9ZHZgU.js +62 -0
  96. package/web-dist/assets/chunk-ZIRB5QZD-C6fEPe3t.js +32 -0
  97. package/web-dist/assets/classDiagram-OUVF2IWQ-GaOJNgfE.js +1 -0
  98. package/web-dist/assets/classDiagram-v2-EOCWNBFH-GaOJNgfE.js +1 -0
  99. package/web-dist/assets/cose-bilkent-JH36ORCC-BUIsLrGc.js +1 -0
  100. package/web-dist/assets/cynefin-VYW2F7L2-COSC0oNL.js +1 -0
  101. package/web-dist/assets/cynefinDiagram-TSTJHNR4-mInhJdg1.js +62 -0
  102. package/web-dist/assets/cytoscape.esm-B3I8pqwA.js +321 -0
  103. package/web-dist/assets/dagre-CXRCoUWR.js +1 -0
  104. package/web-dist/assets/dagre-VKFMJZFB-D-T5z05M.js +4 -0
  105. package/web-dist/assets/defaultLocale-C8Fc0cco.js +1 -0
  106. package/web-dist/assets/diagram-FQU43EPY-HbMkSb3j.js +3 -0
  107. package/web-dist/assets/diagram-G47NLZAW-DBwZLcZh.js +24 -0
  108. package/web-dist/assets/diagram-NH7WQ7WH-DG_Mhays.js +24 -0
  109. package/web-dist/assets/diagram-OA4YK3LP-hH39gqpu.js +30 -0
  110. package/web-dist/assets/diagram-WEI45ONY-DhKZuwxW.js +41 -0
  111. package/web-dist/assets/dist-DoH_9pyS.js +1 -0
  112. package/web-dist/assets/ebnfDiagram-CCIWWBDH-B7BiO-NR.js +1 -0
  113. package/web-dist/assets/erDiagram-Q63AITRT-DHjG5RDQ.js +85 -0
  114. package/web-dist/assets/eventmodeling-45OFAUF4-C0eV8RBx.js +1 -0
  115. package/web-dist/assets/flowDiagram-23GEKE2U-BbldRZUK.js +1 -0
  116. package/web-dist/assets/ganttDiagram-NO4QXBWP-BZ-98wTa.js +292 -0
  117. package/web-dist/assets/gitGraph-TEB2WS4Q-nF22R2jO.js +1 -0
  118. package/web-dist/assets/gitGraphDiagram-IHSO6WYX-CoYQQ22V.js +106 -0
  119. package/web-dist/assets/graphlib-B8gBHxth.js +1 -0
  120. package/web-dist/assets/index-BHzIN-tQ.js +357 -0
  121. package/web-dist/assets/index-Duiy4w7C.css +1 -0
  122. package/web-dist/assets/info-DKCQHKI2-Cy2BCbBW.js +1 -0
  123. package/web-dist/assets/infoDiagram-FWYZ7A6U-CmhR2R1x.js +2 -0
  124. package/web-dist/assets/init-D6jRqBbL.js +1 -0
  125. package/web-dist/assets/ishikawaDiagram-FXEZZL3T-CfG59afl.js +70 -0
  126. package/web-dist/assets/journeyDiagram-5HDEW3XC-BvFmG20q.js +139 -0
  127. package/web-dist/assets/kanban-definition-HUTT4EX6-BHGEecsY.js +89 -0
  128. package/web-dist/assets/katex-CddkPoXu.js +257 -0
  129. package/web-dist/assets/line-Ds4xvN3d.js +1 -0
  130. package/web-dist/assets/linear-z2V0wJk9.js +1 -0
  131. package/web-dist/assets/map-DsCK-0Cs.js +1 -0
  132. package/web-dist/assets/mermaid-parser.core-Gow4kgYJ.js +7 -0
  133. package/web-dist/assets/mermaid.core-B7Qc_kbm.js +11 -0
  134. package/web-dist/assets/mindmap-definition-LN4V7U3C-ayXKGcy_.js +96 -0
  135. package/web-dist/assets/ordinal-hYBb2elL.js +1 -0
  136. package/web-dist/assets/packet-7NZHBO7P-oLBdtkD8.js +1 -0
  137. package/web-dist/assets/path-BWPyau1x.js +1 -0
  138. package/web-dist/assets/pegDiagram-2B236MQR-DwJyc_1B.js +1 -0
  139. package/web-dist/assets/pie-RZYD4A2V-CXzad3fT.js +1 -0
  140. package/web-dist/assets/pieDiagram-ENE6RG2P-CZzgSGtM.js +39 -0
  141. package/web-dist/assets/quadrantDiagram-ABIIQ3AL--IPIp8yo.js +7 -0
  142. package/web-dist/assets/radar-I7S5WNFK-DldySvtZ.js +1 -0
  143. package/web-dist/assets/railroad-3IZDKUUU-CiWFZfXM.js +1 -0
  144. package/web-dist/assets/railroad-abnf-AHOZXSZD-bXMYUOCD.js +1 -0
  145. package/web-dist/assets/railroad-ebnf-EBAXGLYW-D11ZwZby.js +1 -0
  146. package/web-dist/assets/railroad-peg-LSFZ7HO6-DD1AC5X-.js +1 -0
  147. package/web-dist/assets/railroadDiagram-RFXS5EU6-DcCMNGGb.js +1 -0
  148. package/web-dist/assets/requirementDiagram-TGXJPOKE-C-6j8urk.js +84 -0
  149. package/web-dist/assets/rolldown-runtime-Bh1tDfsg.js +1 -0
  150. package/web-dist/assets/rough.esm-CSKSodPl.js +1 -0
  151. package/web-dist/assets/sankeyDiagram-HTMAVEWB-CPtiOpdz.js +40 -0
  152. package/web-dist/assets/sequenceDiagram-DBY2YBRQ-B8FnQTdn.js +162 -0
  153. package/web-dist/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
  154. package/web-dist/assets/src-C4XfhTaE.js +1 -0
  155. package/web-dist/assets/stateDiagram-2N3HPSRC-CxG9nX2P.js +1 -0
  156. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-SGarOFIy.js +1 -0
  157. package/web-dist/assets/swimlanes-5IMT3BWC-D49-t0hV.js +2 -0
  158. package/web-dist/assets/swimlanesDiagram-G3AALYLV-krF0bh4b.js +8 -0
  159. package/web-dist/assets/timeline-definition-FHXFAJF6-C9OEd9SE.js +120 -0
  160. package/web-dist/assets/treeView-QDETBFTQ-D1AKqVPa.js +1 -0
  161. package/web-dist/assets/treemap-6X3UGDF4-BRssB7hM.js +1 -0
  162. package/web-dist/assets/vennDiagram-L72KCM5P-CftkAbY0.js +34 -0
  163. package/web-dist/assets/wardley-OPB4EBWU-RLMgzRq4.js +1 -0
  164. package/web-dist/assets/wardleyDiagram-EHGQE667-BLytgXPS.js +78 -0
  165. package/web-dist/assets/xychartDiagram-FW5EYKEG-BYgK1Y3H.js +7 -0
  166. package/web-dist/favicon-16.png +0 -0
  167. package/web-dist/favicon-32.png +0 -0
  168. package/web-dist/favicon.svg +78 -0
  169. package/web-dist/icon-192.png +0 -0
  170. package/web-dist/icon-512.png +0 -0
  171. package/web-dist/icon-maskable-512.png +0 -0
  172. package/web-dist/index.html +33 -0
  173. package/web-dist/manifest.webmanifest +16 -0
@@ -0,0 +1,203 @@
1
+ ---
2
+ name: handoff
3
+ description: The full fray end-of-turn signal reference for a fray-ui worker (invoke as fray:handoff) — every `awaiting` hint kind, the `question` fence tags (`danger`, `multi`), `done` body formatting, and worked examples of each. Your system-prompt contract carries the rules you need for the common case; load this when you are emitting an unusual fence, need a worked example of a tagged question card, or are unsure which fence a situation calls for.
4
+ ---
5
+
6
+ # fray handoff reference
7
+
8
+ Your system prompt states the fence rules. This is the elaboration: the exact shapes, the tags, and
9
+ worked examples. Nothing here overrides the contract.
10
+
11
+ ## Which fence?
12
+
13
+ | Situation | Fence |
14
+ |---|---|
15
+ | Ordinary handoff, turn has no other final state | **bare rest** (no fence) |
16
+ | Effort's real work is complete — code merged, plan/doc written, commissioned report finished | `done` |
17
+ | Waiting on a named third-party human, a wall-clock instant, or a PR's review | `awaiting` |
18
+ | You need the operator's input or approval | `question` |
19
+ | Mid-conversation (still working, or answering and continuing) | none |
20
+
21
+ Automatable waits — CI, releases, deploys, merge progression — are **never** `awaiting`. Dispatch a
22
+ sub-agent to own the wait, or use a `timer:` when the next check belongs at a later wall-clock time.
23
+
24
+ ## `done`
25
+
26
+ Body is a bullet list, one `- ` item per completed task, each naming what shipped and where. The card
27
+ renders inline markdown: backtick every path/identifier/command, and make references real links.
28
+
29
+ ```done
30
+ - Fixed the cache collision in [`src/resolver.ts`](https://github.com/acme/app/pull/391) — the lookup now keys on the normalized id.
31
+ - Added a regression test for the collision case; `npm test` green.
32
+ - Self-review folded in; `npm run lint` clean.
33
+ ```
34
+
35
+ Do not write a narrative paragraph. Do not fence `done` on work that is not landed.
36
+
37
+ ## `awaiting` — the three hint kinds
38
+
39
+ Lead the body with one or more `kind: value` lines, then prose naming the exact wake condition.
40
+
41
+ `pr-watch: owner/repo#NUMBER` — fray polls the PR and resumes you on ANY new activity after the fence:
42
+ a review, an approval, or a comment, from a **human or a bot alike** (review agents that post findings
43
+ as a conversation comment count exactly like a human reviewer). Baselined at the fence and durable
44
+ across a server/worker restart. Your thread **stays in the queue** as a visible "PR is up, watching it"
45
+ handoff — it does not hide in Held, because a PR whose reviews may never arrive must not silently
46
+ vanish. The human can Snooze it; new activity bumps it back.
47
+
48
+ ```awaiting
49
+ pr-watch: acme/app#391
50
+ PR is open and CI is green. Watching for review — I'll address comments or merge on approval.
51
+ ```
52
+
53
+ **One line watches one PR, and a fence may carry several.** The scheduler evaluates every hint in the
54
+ body, so repeat the line per PR — across any mix of repos — and activity on ANY of them wakes you. A
55
+ set of open PRs is NOT a reason to fall back to a periodic `timer:` sweep, which trades instant wakes
56
+ for a poll that can sit a day behind a review. The body keeps its first **8** hint lines and silently
57
+ drops the rest, so past 8 watch the 8 that matter and cover the tail with a `timer:`.
58
+
59
+ ```awaiting
60
+ pr-watch: withastro/astro#17487
61
+ pr-watch: vitejs/vite#23019
62
+ pr-watch: strapi/strapi#26864
63
+ All three adoption PRs are open and green, in their maintainers' hands. Whichever gets a review first
64
+ wakes me and I'll address it.
65
+ ```
66
+
67
+ `human: <actor + exact review/approval>` — a third party whose action cannot be supplied in this fray
68
+ conversation. **Parks you in the dimmed Held band.** A bot, automated reviewer, CI gate, or merge queue
69
+ is NOT a human wait. Pair with `pr-watch:` when a machine-readable PR exists (the `human:` supplies the
70
+ Held park, the `pr-watch:` supplies the cursor), or with `timer:` when none does.
71
+
72
+ ```awaiting
73
+ human: dependabot maintainer review on dependabot/dependabot-core#15524
74
+ pr-watch: dependabot/dependabot-core#15524
75
+ The implementation and actionable checks are complete; address requested changes when review lands.
76
+ ```
77
+
78
+ `timer: <ISO-8601 instant>` — the durable fray scheduler resumes you at that instant, across process
79
+ exits and restarts. The prose says exactly what to re-check.
80
+
81
+ ```awaiting
82
+ timer: 2026-07-15T17:00:00Z
83
+ Re-check whether the external maintainer review arrived and reclassify any new failure.
84
+ ```
85
+
86
+ `pr:` / `ci:` / `session:` remain parser compatibility for existing transcripts only. Never emit them.
87
+
88
+ ### Re-entering a wait after a follow-up
89
+
90
+ Every human follow-up clears the previous fence. Never answer that you are "already parked" and never
91
+ rely on the old fence, scratchpad, or thread status: re-check the blocker, then either re-emit a fresh
92
+ `awaiting` with a current hint, or arm the active wait if it turns out to be automatable.
93
+
94
+ ## `question` — the tags
95
+
96
+ Plain — an open question:
97
+
98
+ ```question
99
+ Should the settings store use SQLite or a JSON file?
100
+
101
+ - A. SQLite — transactional, matches how sessions are already stored (recommended: consistency)
102
+ - B. JSON file — zero deps, human-editable, racy under concurrent writes
103
+ ```
104
+
105
+ A GO/NO-GO gate has NO tag of its own — it is a plain `question` with two options, the go and the
106
+ decline. (There used to be an `approval` tag rendering one Approve button that SENT on click; it was
107
+ dropped 2026-07-26 because it couldn't express the decline and it bypassed the staging every other
108
+ block uses. A legacy `approval` token still parses — as a plain question — so old transcripts render,
109
+ but never write one.)
110
+
111
+ ```question
112
+ Ready to create CONTRIBUTING.md with the draft above?
113
+
114
+ - A. Approve as-is (recommended)
115
+ - B. Hold — tell me what to change first
116
+ ```
117
+
118
+ `danger` — reserve for the genuinely hard-to-undo (force-merge, deletion, history rewrite,
119
+ prod rollback). Renders in red. A routine ship is a plain question:
120
+
121
+ ```question danger
122
+ Force-merge PR #391 over the failing flaky check and delete the `legacy-api` branch?
123
+
124
+ - A. Do it — the failure is the known-flaky timeout
125
+ - B. Hold — I'll wait for a green run
126
+ ```
127
+
128
+ `multi` — select-several triage. Options render as checkboxes; the answer returns the chosen letters:
129
+
130
+ ```question multi
131
+ Which of these findings should I fix in this pass?
132
+
133
+ - A. Null-deref in parse() — crashes on empty input
134
+ - B. Off-by-one in slice() — drops the last row
135
+ - C. Flaky timeout in the retry test — passes on rerun
136
+ ```
137
+
138
+ ### Rules that apply to every question
139
+
140
+ - Open the message with 2-4 sentences of status before the blocks.
141
+ - One block per independent question — never bundle.
142
+ - Lettered options, one markdown list item each, with a one-line tradeoff.
143
+ - Mark exactly one option `recommended` **on that option's line**, and put it first as `A`. Use
144
+ `(recommended: one-line why)` to carry the rationale into the chip's tooltip. Do not use a separate
145
+ `Recommendation:` line.
146
+ - Answerable COLD, in the human's own vocabulary — see the next section.
147
+ - A question IS the handback: no second fence.
148
+ - Before you write one, re-read the stop criterion. A question about work you were dispatched to do,
149
+ or a fix you already recommend, is not a question.
150
+
151
+ ### Write it in the human's own vocabulary
152
+
153
+ The reader has their original prompt and nothing else — not your plan, not your scratchpad, not the
154
+ transcript, not the names you settled on while working. A question that reads perfectly from inside the
155
+ session is routinely unanswerable from outside it. This is the most common defect in real question
156
+ cards, and it is entirely a wording problem: the decision was fine, the phrasing made it unavailable.
157
+
158
+ - **Translate the nomenclature you coined mid-effort.** Anything you named while working is invisible to
159
+ the reader: phase / lane / tier / mode names, step or section numbers, "the C path", "the second
160
+ variant", "the reconciler", "option 3 from earlier", "as in §2 of the plan". They will not go read your
161
+ transcript to decode it, so say what the thing does instead of what you called it.
162
+ - **Minimize code identifiers; default to plain behavior.** File paths, function / type / component
163
+ names, flags, env vars, table and column names usually cost the reader more than they give — lead with
164
+ the behavior. Spend an identifier where it genuinely earns its place: the human already uses it, or the
165
+ decision is literally about that name (they asked you to rename it, or to pick a flag's spelling). One
166
+ well-chosen identifier is fine; a card assembled out of them is the failure mode.
167
+ - **Carry every decision input inside the block.** What happens today, each option's user-visible
168
+ consequence, the cost of guessing wrong, and any number that matters. "As discussed above", a pointer
169
+ to a file, or a reference to an earlier turn all point at something the reader cannot see from the card.
170
+ - **Define a load-bearing new term, or drop it.** If one unfamiliar word genuinely cannot be avoided,
171
+ define it in the same sentence. Otherwise it is decoration, and it costs you the answer.
172
+
173
+ Bad — every noun here was invented during the effort, so the reader has no way into it:
174
+
175
+ ```question
176
+ Should the queue lane keep the tier-2 fallback from step 3, or move to the unified resolver?
177
+
178
+ - A. Keep the tier-2 fallback (recommended)
179
+ - B. Move to the unified resolver
180
+ ```
181
+
182
+ Good — same decision, stated in terms the human already owns:
183
+
184
+ ```question
185
+ When you've read everything in a thread, should it stay in the "needs attention" group until you archive it, or drop out on its own?
186
+
187
+ - A. Drop out once it's read (recommended: keeps the group to threads that still need you)
188
+ - B. Stay until archived — nothing ever disappears without you acting on it
189
+ ```
190
+
191
+ (That question line is deliberately unwrapped. Inside a fence a single newline is a HARD break —
192
+ `breaks: true` in the web markdown renderer — so hard-wrapping the sentence at your editor's column
193
+ renders a ragged break mid-question in the card. Keep the question, and each option, on one line.)
194
+
195
+ Test it before you send: read the block with your session forgotten, as if it were the only thing you
196
+ had ever seen about this work. Any word that only means something because of what you just did is a word
197
+ to reword.
198
+
199
+ ## Never use the interactive question tool
200
+
201
+ `AskUserQuestion` (or any blocking prompt tool) would hang your session invisibly under the dashboard.
202
+ It is removed from your tool set at spawn; if you somehow reach it, a hook denies it. Use a `question`
203
+ fence.
@@ -0,0 +1,83 @@
1
+ ---
2
+ name: waits
3
+ description: How a fray-ui worker waits on something without going silent or falling out of the board's Active state (invoke as fray:waits) — choosing between a wait-owning sub-agent, background Bash, native Monitor, and a durable timer fence; fray's portable monitor scripts; and the CI/PR/release recipes. Load this when your effort needs to wait on CI, a release, a deploy, a merge, or another long-running condition.
4
+ ---
5
+
6
+ # Waiting, without going silent
7
+
8
+ Your system prompt carries the one rule that decides the mechanism. This is the playbook.
9
+
10
+ ## The rule
11
+
12
+ **Only a live dispatched sub-agent keeps a rested thread out of the human's queue.** A background
13
+ `Bash`/`Monitor` does not: `run_in_background` means "don't block my turn", and fray cannot tell a CI
14
+ watcher that ends in minutes from a `vite` dev server that runs forever, so neither holds a rested
15
+ thread in Active.
16
+
17
+ | You will… | Use |
18
+ |---|---|
19
+ | REST until the condition is met (the usual CI / PR / release wait) | a **sub-agent** that owns the wait |
20
+ | KEEP WORKING alongside a process you launched (dev server, log tail) | `Bash` + `run_in_background: true` |
21
+ | stream events into the turn you are actively working in | `Monitor` |
22
+ | re-check at a named wall-clock instant, across a process exit | `timer:` awaiting fence |
23
+
24
+ Never fake a wait with `echo waiting`, repeated foreground sleeps, or an `awaiting` fence for CI, bots,
25
+ releases, or merge progression.
26
+
27
+ Never fake Claude's native background mechanism with shell job control (`cmd &`, `nohup … &`, or
28
+ `disown`). The child may survive after Bash returns, but it has no Claude task id, output-file
29
+ lifecycle, completion notification, or wake. Use `run_in_background: true` with the long command
30
+ itself in the foreground. Shell-level concurrency is only self-contained: explicitly `wait` for its
31
+ children or own cleanup with an EXIT trap before that Bash call returns.
32
+
33
+ ## Choosing a monitor implementation
34
+
35
+ 1. **Look for project-declared tooling first** — `AGENTS.md`, project skills, docs, package scripts.
36
+ Prefer it only after validating its absolute command and its terminal event/exit semantics. Invalid
37
+ declared tooling is a visible configuration error to report, not something to silently shadow. Never
38
+ select a monitor merely by filename.
39
+ 2. **Otherwise use fray's portable Node scripts** in `monitors/` (zero-dep, NDJSON on stdout, they exit
40
+ at a terminal verdict).
41
+ 3. **Native `Monitor`** is the Claude adapter for a changing condition — a quiet
42
+ `until ...; do sleep ...; done`, emitting one event per meaningful transition. `persistent: true`
43
+ runs until `TaskStop` or session end.
44
+
45
+ ## The sub-agent-owns-the-wait pattern
46
+
47
+ This is the prescribed way to wait while you rest. Dispatch with the plain Agent tool +
48
+ `run_in_background: true`, no `name` field. The child runs the watcher in **its own foreground** and
49
+ returns the verdict; you stay Active, and its return re-invokes you so you can act on the result.
50
+
51
+ Foreground Bash is timeout-capped at ~10 minutes, so for a longer wait the child must loop until its
52
+ terminal condition rather than issuing one long call. A helper must not hand back its final report
53
+ while its own watcher is still live — the wait IS its work.
54
+
55
+ Give the child, literally, in the prompt:
56
+
57
+ - the exact command to run and the terminal condition to stop on;
58
+ - the repo path and the scratchpad path;
59
+ - what to return: the verdict plus enough detail to act on a failure (job name, failing step, log tail);
60
+ - an instruction not to fix anything — it observes and reports; you decide.
61
+
62
+ ## Recipes
63
+
64
+ **GitHub CI on a PR head.** `gh run watch <run-id> --exit-status` blocks to completion, or loop
65
+ `gh pr checks <n> --json name,state,link`. A partial `gh pr checks` rollup is **not** a green verdict:
66
+ also inspect the workflow runs for the exact PR head, and treat `ACTION_REQUIRED` fork gates as pending,
67
+ not passing.
68
+
69
+ **PR review activity.** Do not build a watcher — emit `awaiting` with `pr-watch: owner/repo#N` and fray
70
+ polls it for you, waking on any new review, approval, or comment, bot or human. See `fray:handoff`.
71
+
72
+ **A release or deploy.** Poll the artifact that proves it, not the pipeline that promises it — the
73
+ published version on the registry, the health endpoint, the deployed asset hash.
74
+
75
+ **Another long-running local process.** Read its output path with `Read` for diagnostics (`TaskOutput`
76
+ is deprecated). `TaskStop` is only for your own monitor after its terminal handoff — never to cut off a
77
+ sub-agent or a writer.
78
+
79
+ ## Liveness caveats
80
+
81
+ Live tasks do not survive the Claude process or session ending. A durable `timer:` fence is the only
82
+ wait that survives a restart, so use it when the next meaningful check genuinely belongs at a later
83
+ instant rather than continuously monitored now.
Binary file