@jeffober/thatch 0.1.34 → 0.1.36

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.
@@ -47,7 +47,7 @@ description: Extract durable project facts ... Use when ...
47
47
  | `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
48
48
  | `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar against generic praise. |
49
49
  | `thatch-review-synthesizer` | Verify specialist findings against code, dedupe, classify, calibrate severity. Starts the final report with a workflow-change preface, then cross-references findings against prior review comments when a follow-up round register is provided. |
50
- | `thatch-review-context` | Gather project/feature context (PR descriptions, git archaeology, ticket references, memory) before fan-out. Prevents false positives about intentionally deferred work. Also fetches prior review comments on a connected PR/MR for follow-up-round detection and builds a register with preliminary addressed-check status per comment. |
50
+ | `thatch-review-context` | Gather project/feature context (PR descriptions, git archaeology, ticket references, linked docs/tickets followed from the change, memory) before fan-out. Prevents false positives about intentionally deferred work, and checks whether main moved past the merge-base touching the same paths (staleness signal for the synthesizer). Also fetches prior review comments on a connected PR/MR for follow-up-round detection and builds a register with preliminary addressed-check status per comment. |
51
51
  | `thatch-code-archaeology` | Investigate an existing feature, debug an unfamiliar area, or begin a new ticket. Explores the code base from multiple angles (data model, state flow, git history, sibling features, skeletons) before proposing changes. The research skill; pair with `thatch-coding-workflow`. |
52
52
  | `thatch-review-followup` | Alternate entrypoint for follow-up review rounds. Verifies whether the author's responses and code changes since your last review round adequately addressed your prior findings, offers to reply on resolved items, then optionally re-runs the full structured review. |
53
53
  | `thatch-change-walkthrough` | Explain a change to the user as a teaching walkthrough: resolve the delta, research each affected workflow at the merge-base, teach current behavior, then overlay the modifications with file:line citations and analogies. |
@@ -119,10 +119,12 @@ and `--cursor` pass only the shared set.
119
119
  versions without users manually deleting files.
120
120
  - **Stale cleanup**: before installing, `installSkills` removes stale skill
121
121
  directories. Any `thatch-*` directory not in the current install set is
122
- deleted (the `thatch-` prefix is our namespace). Three skills renamed from
123
- non-prefixed to `thatch-`-prefixed in v0.1.27 (pr-description, ticket-description,
124
- split-overlarge-pr) are also cleaned up through v0.1.35; after that, those
125
- names are fair game for third parties and the cleanup stops.
122
+ deleted (the `thatch-` prefix is our namespace). Non-prefixed directories
123
+ are never touched: the v0.1.27 rename migration (pr-description,
124
+ ticket-description, split-overlarge-pr) cleaned up old installs only
125
+ through a version window that closed with v0.1.35, after which those names
126
+ are fair game for third parties and the cleanup no longer runs. Users
127
+ upgrading from before v0.1.27 delete the old directories manually.
126
128
  - **Idempotent**: re-running init or setup overwrites drifted content but leaves
127
129
  unrelated (non-`thatch-*`) skill files alone.
128
130
 
@@ -11,6 +11,7 @@ This README is the overview. Each feature has its own guide:
11
11
 
12
12
  - [memory.md](memory.md): persistent memory store
13
13
  - [extraction.md](extraction.md): automatic fact extraction from tool calls
14
+ - [watchers.md](watchers.md): event-driven notifications (PR watching)
14
15
  - [prediction-engine.md](prediction-engine.md): user decision model
15
16
  - [behavior-engine.md](behavior-engine.md): agent self-discipline rules
16
17
  - [default-behaviors.md](default-behaviors.md): what ships automatically
@@ -142,6 +143,29 @@ Stores are created automatically. No setup required.
142
143
  | `thatch_behavior_list` | List all codified behaviors with matchers, confidence, and provenance. |
143
144
  | `thatch_behavior_delete` | Delete a behavior by semantic match. Edges and provenance are cascade-deleted. |
144
145
 
146
+ ### Session tools (opencode only)
147
+
148
+ | Tool | What it does |
149
+ |------|-------------|
150
+ | `thatch_get_session_info` | Report the current session's ID and the agent name running this turn. opencode doesn't surface its session ID to the model; the agent needs it to fetch extraction payloads or look up past sessions. MCP hosts have no session concept, so this tool doesn't exist there. |
151
+ | `thatch_session_search` | Search past opencode conversations by substring or regex. Matches decoded message text, tool outputs, and reasoning across all sessions. Returns JSONL hits with ids for follow-up. |
152
+ | `thatch_session_get` | Retrieve the full content of one part or message found via `thatch_session_search`, including complete tool inputs and outputs. |
153
+
154
+ The same functionality is available on the command line as `thatch session
155
+ list`, `thatch session get`, `thatch session transcript`, and `thatch session
156
+ search` - JSONL output designed for piping to `jq` or `grep`.
157
+
158
+ ### Watcher tools (opencode only)
159
+
160
+ | Tool | What it does |
161
+ |------|-------------|
162
+ | `thatch_watch_create` | Watch a GitHub PR for events (comments, review comments and replies, commits, status changes, description edits, CI completions). The plugin polls in the background and prompts the session when a watched event happens. |
163
+ | `thatch_watch_list` | List this session's active watchers. |
164
+ | `thatch_watch_cancel` | Cancel one of this session's watchers by id. |
165
+
166
+ See [watchers.md](watchers.md) for the full behavior, lifetime, and
167
+ requirements.
168
+
145
169
  ## Automatic behaviors
146
170
 
147
171
  Beyond the tools, thatch hooks into opencode itself:
@@ -237,7 +261,7 @@ response, walkthrough, and workflow skills that support the review pipeline:
237
261
  | `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
238
262
  | `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar against generic praise. |
239
263
  | `thatch-review-synthesizer` | Verifies and synthesizes findings from multiple specialists into a report that starts with workflow changes, then highlights, then deduplicated severity-grouped findings. |
240
- | `thatch-review-context` | Gathers project context (PR descriptions, git archaeology, ticket references, memory) before a review. Prevents false positives about intentionally deferred work. |
264
+ | `thatch-review-context` | Gathers project context (PR descriptions, git archaeology, ticket references, linked docs/tickets, memory) before a review. Prevents false positives about intentionally deferred work. |
241
265
  | `thatch-code-archaeology` | Investigates an existing feature, debugs an unfamiliar area, or begins a new ticket. Explores the code base from multiple angles (data model, state flow, git history, sibling features, skeletons) before proposing changes. Pairs with `thatch-coding-workflow`. |
242
266
  | `thatch-review-followup` | Alternate entrypoint for follow-up review rounds. Verifies whether the author's responses and code changes since your last review adequately addressed your prior findings, offers to reply on resolved items, then optionally re-runs the full structured review. |
243
267
  | `thatch-review-response` | Author-side review response: triage findings on your own PR, fix bugs one by one, reply on each thread, post a top-level summary comment. |
@@ -10,9 +10,15 @@ The coordinator skill (`thatch-code-review`, opencode-only) orchestrates
10
10
  the review:
11
11
 
12
12
  1. **Resolve the target**: fetch origin, compute merge-base against
13
- `origin/main`, support branch/PR/explicit range.
13
+ `origin/main`, support branch/PR/explicit range. All file reads and
14
+ comment anchors are computed against the PR head ref, not the
15
+ working tree, which may be checked out on a different branch.
14
16
  2. **Gather project context**: PR descriptions, git archaeology,
15
- ticket references, TODO markers, prior reviews, project memory.
17
+ ticket references, links to docs/designs/tickets found in the
18
+ change (followed one hop for scope and design context), TODO
19
+ markers, prior reviews, project memory. Also checks whether main
20
+ has moved past the merge-base touching the same paths — a stale
21
+ branch can make findings true only at the merge-base.
16
22
  3. **Research affected workflows**: load `thatch-code-archaeology`,
17
23
  trace the code paths the change touches.
18
24
  4. **Estimate complexity**: partition the diff into review units.
@@ -21,7 +27,9 @@ the review:
21
27
  6. **Synthesize**: the synthesizer reads all specialist output,
22
28
  verifies each finding (cited text exists, claim is accurate,
23
29
  severity is justified), deduplicates by root cause, and produces
24
- the final report.
30
+ the final report. When the branch is stale relative to main, it
31
+ re-verifies behavioral findings against current main and reports
32
+ merge-base-only findings as rebase notes rather than defects.
25
33
 
26
34
  ## The eight specialists
27
35
 
@@ -46,7 +46,7 @@ becomes part of the agent's context.
46
46
  | `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
47
47
  | `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar. |
48
48
  | `thatch-review-synthesizer` | Verifies and synthesizes findings from multiple specialists into a deduplicated, severity-grouped report. |
49
- | `thatch-review-context` | Gathers project context (PRs, tickets, TODOs, deferred work) before a review. Prevents false positives about intentionally deferred work. |
49
+ | `thatch-review-context` | Gathers project context (PRs, tickets, linked docs/designs followed from the change, TODOs, deferred work) before a review. Prevents false positives about intentionally deferred work. |
50
50
  | `thatch-code-archaeology` | Investigates an existing feature, debugs an unfamiliar area, or begins a new ticket. The research skill; pair with `thatch-coding-workflow`. |
51
51
  | `thatch-review-followup` | Verifies whether the author's responses and code changes since your last review adequately addressed your prior findings. |
52
52
  | `thatch-review-response` | Author-side review response: triage findings on your own PR, fix bugs one by one, reply on each thread, post a top-level summary comment. |
@@ -0,0 +1,79 @@
1
+ # Watchers
2
+
3
+ Watchers monitor external sources - today, GitHub pull requests - and
4
+ inject a notification into the conversation when something happens. You
5
+ ask the agent to watch a PR; thatch polls it in the background; the
6
+ agent gets woken up when a watched event occurs. No one has to keep
7
+ asking "any updates yet?"
8
+
9
+ ## What it does
10
+
11
+ The agent calls `thatch_watch_create` to register a watcher on a PR.
12
+ thatch captures the PR's current state as a baseline, then polls the
13
+ GitHub API through the `gh` CLI once a minute. When the PR changes in a
14
+ way the watcher cares about, the plugin prompts the agent with a
15
+ notification.
16
+
17
+ Watched events:
18
+
19
+ - `pr_comment` - new top-level comments on the PR
20
+ - `pr_review_comment` - new inline comments on the diff
21
+ - `pr_review_reply` - replies to an existing review comment
22
+ - `pr_commit` - new commits (the head SHA moved)
23
+ - `pr_status` - the PR opened, closed, or merged
24
+ - `pr_description` - title or description edited
25
+ - `pr_ci` - a CI check run on the head SHA completed
26
+
27
+ Notifications are delivered as synthetic parts: the model sees them,
28
+ the transcript does not. A notification triggers a model turn, so the
29
+ agent can act on the event even while you are away.
30
+
31
+ ## Privacy model
32
+
33
+ Notifications carry pointer data only: who commented, what happened,
34
+ and a URL. Comment bodies, diff contents, and CI logs never enter the
35
+ context from the notification itself. This is deliberate - GitHub
36
+ comments are written by strangers, and untrusted text flowing into a
37
+ model's context is a prompt-injection vector. The agent fetches details
38
+ on demand with `gh` when it decides to act.
39
+
40
+ ## How to use it
41
+
42
+ Ask for it in conversation:
43
+
44
+ > Watch PR 1234 for review comments. If bugbot comments, handle it
45
+ > yourself. If a human comments, just tell me.
46
+
47
+ The handling policy lives in your instruction. State it when you ask -
48
+ the notification turn reads your policy from the conversation and
49
+ follows it. The notification says what happened and where, not what to
50
+ do about it.
51
+
52
+ Other tools:
53
+
54
+ - `thatch_watch_list` - shows the session's active watchers
55
+ - `thatch_watch_cancel` - cancels one by id
56
+
57
+ ## Lifetime
58
+
59
+ Watchers are in-memory and process-scoped:
60
+
61
+ - Ending the opencode process (or restarting it) drops all watchers.
62
+ - A watcher expires after 8 hours by default.
63
+ - Each session can hold up to 5 active watchers.
64
+
65
+ If opencode restarts while a watch is active, re-register it - the
66
+ session's conversation survives, so the policy you stated is still
67
+ there.
68
+
69
+ ## Requirements and limitations
70
+
71
+ - **opencode only.** MCP hosts (Claude Code, Cursor) have no way for a
72
+ plugin to start a conversation turn, so the watch tools are not
73
+ available there.
74
+ - **Requires the `gh` CLI** to be installed and authenticated. Watch
75
+ creation reports a clear error if it is not.
76
+ - **Polling, not webhooks.** Events appear on the next poll cycle
77
+ (60 seconds by default), not instantly.
78
+ - **No delivery during an active turn.** If the agent is mid-turn when
79
+ an event fires, the notification waits until the turn ends.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeffober/thatch",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "description": "Persistent memory for AI coding agents — local embeddings, SQLite stores, zero config. Works with OpenCode (as a plugin), Claude Code (as an MCP server), and Cursor (as an MCP server).",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/index.ts CHANGED
@@ -21,6 +21,8 @@ import { installSkills, SHARED_SKILLS, OPENCODE_ONLY_SKILLS } from "./skills";
21
21
  import { hygieneReport } from "./hygiene";
22
22
  import { seedDefaultBehaviors } from "./seed-behaviors";
23
23
  import { startVersionChecker, stopVersionChecker, getVersionChecker, readOnDiskVersion, compareSemver } from "./version-check";
24
+ import { WatcherRegistry, ghApiRun, ghAvailable } from "./watchers";
25
+ import { watcherNotificationNudge } from "./prompts";
24
26
  import pkg from "../package.json";
25
27
 
26
28
  // ---------------------------------------------------------------------------
@@ -83,6 +85,43 @@ export const server: Plugin = async ({ client, worktree }) => {
83
85
  // non-restart.
84
86
  const runningVersion = pkg.version;
85
87
 
88
+ // Latest observed opencode session status per session ("busy" | "idle" |
89
+ // "retry"). The event hook records these; the watcher registry's
90
+ // canDeliver gate reads them so proactive notification prompts only fire
91
+ // into idle sessions - never into a turn that is already running.
92
+ const sessionStatus = new Map<string, string>();
93
+
94
+ // In-memory watcher registry for proactive event notifications (GitHub PR
95
+ // watching today). Deliberately process-scoped: no SQLite, no cross-restart
96
+ // state. See src/watchers.ts for the rationale.
97
+ //
98
+ // Delivery prompts the session with a synthetic part - the same mechanism
99
+ // opencode uses for background task completions - so a watched event
100
+ // triggers a model turn even when the user is away. Events only carry
101
+ // pointer data; the model fetches details itself with gh.
102
+ const watchers = new WatcherRegistry({
103
+ deliver: async (sessionID, events) => {
104
+ const target = events[0]?.url.match(/github\.com\/([^/]+\/[^/]+)\/pull\/(\d+)/)?.[0]
105
+ ?.replace(/github\.com\//, "")
106
+ .replace(/\/pull\//, "#") ?? "watched PR";
107
+ await client.session.promptAsync({
108
+ path: { id: sessionID },
109
+ body: {
110
+ parts: [{ type: "text", text: watcherNotificationNudge(target, events), synthetic: true }],
111
+ },
112
+ });
113
+ },
114
+ canDeliver: (sessionID) =>
115
+ !compacting.has(sessionID) && sessionStatus.get(sessionID) === "idle",
116
+ ghRunner: ghApiRun,
117
+ });
118
+ // gh presence decides whether watch_create works; checked lazily by the
119
+ // tool, but log once at startup so misconfiguration is visible in debug logs.
120
+ void ghAvailable().then((ok) => {
121
+ if (!ok) console.error("[thatch] gh CLI not found - watch tools will report unavailable");
122
+ });
123
+ watchers.start();
124
+
86
125
  // Sessions currently being compacted. chat.message nudges are skipped while
87
126
  // a session is in this set - the agent can't call tools during summary
88
127
  // generation, so a recall or extraction nudge would cause a blocked-tool
@@ -242,6 +281,7 @@ export const server: Plugin = async ({ client, worktree }) => {
242
281
  if (all.length === 0) return null;
243
282
  return extraction.buildPayload(all, repo);
244
283
  },
284
+ watcherRegistry: watchers,
245
285
  }),
246
286
 
247
287
  // 1. System prompt - always in context.
@@ -600,8 +640,13 @@ export const server: Plugin = async ({ client, worktree }) => {
600
640
  }
601
641
  return;
602
642
  }
603
- if (event.type === "session.status" && event.properties.status?.type === "idle") {
643
+ if (event.type === "session.status") {
604
644
  const sessionID = event.properties.sessionID;
645
+ const statusType = event.properties.status?.type;
646
+ // Record the latest status so the watcher registry can gate
647
+ // proactive prompt delivery on idle sessions.
648
+ if (sessionID && statusType) sessionStatus.set(sessionID, statusType);
649
+ if (statusType !== "idle") return;
605
650
  const parentID = sessionID ? childToParent.get(sessionID) : undefined;
606
651
  if (parentID && sessionID) {
607
652
  // A child session went idle. Two cases:
@@ -685,6 +730,15 @@ export const server: Plugin = async ({ client, worktree }) => {
685
730
  extracting.delete(sessionID);
686
731
  }
687
732
  }
733
+ // The session just became idle, so watcher events queued while it
734
+ // was busy can be delivered now - the poll interval may otherwise
735
+ // hold them for up to a full cycle. Best-effort; failures stay
736
+ // pending and retry on the next poll.
737
+ try {
738
+ await watchers.deliverPending();
739
+ } catch (err) {
740
+ console.error(`[thatch] watcher delivery on idle failed: ${err}`);
741
+ }
688
742
  return;
689
743
  }
690
744
  if (event.type === "session.deleted") {
@@ -699,9 +753,13 @@ export const server: Plugin = async ({ client, worktree }) => {
699
753
  parentSnapshots.delete(id);
700
754
  childMetrics.delete(id);
701
755
  extractionChildren.delete(id);
702
- // A deleted parent takes its accepted entries with it.
756
+ // A deleted parent takes its accepted entries with it, and its
757
+ // watchers die with it - the session that would receive their
758
+ // notifications no longer exists.
703
759
  extraction.completeAccepted(id);
704
760
  extracting.delete(id);
761
+ sessionStatus.delete(id);
762
+ watchers.cancelSession(id);
705
763
  return;
706
764
  }
707
765
 
@@ -739,6 +797,7 @@ export const server: Plugin = async ({ client, worktree }) => {
739
797
 
740
798
  dispose: async () => {
741
799
  stopVersionChecker();
800
+ watchers.dispose();
742
801
  db.close();
743
802
  },
744
803
  };
package/src/mcp.ts CHANGED
@@ -60,9 +60,12 @@ interface CompiledTool {
60
60
  inputSchema: Record<string, unknown>;
61
61
  }
62
62
 
63
- function compileTools(): Map<string, CompiledTool> {
63
+ export function compileTools(): Map<string, CompiledTool> {
64
64
  const map = new Map<string, CompiledTool>();
65
65
  for (const def of TOOL_DEFS) {
66
+ // opencode-only tools depend on host capabilities MCP servers don't
67
+ // have (e.g. session identity via HostToolContext) - never expose them.
68
+ if (def.opencodeOnly) continue;
66
69
  const schema = z.object(def.args);
67
70
  map.set(def.name, {
68
71
  def,
package/src/prompts.ts CHANGED
@@ -17,13 +17,15 @@ Thatch provides persistent memory across opencode sessions. Use it to persist
17
17
  knowledge so future sessions can build on what you've already learned.
18
18
 
19
19
  Tools: thatch_memory_remember, thatch_memory_recall, thatch_memory_list,
20
- thatch_memory_show, thatch_memory_forget, thatch_store_list,
21
- thatch_find_duplicates, thatch_dedup_mark_checked,
22
- thatch_extraction_done, thatch_get_extraction_payload,
23
- thatch_prediction_query, thatch_prediction_update, thatch_prediction_list,
24
- thatch_prediction_delete,
25
- thatch_behavior_codify, thatch_behavior_feedback, thatch_behavior_list,
26
- thatch_behavior_delete
20
+ thatch_memory_show, thatch_memory_forget, thatch_store_list,
21
+ thatch_find_duplicates, thatch_dedup_mark_checked,
22
+ thatch_extraction_done, thatch_get_extraction_payload,
23
+ thatch_prediction_query, thatch_prediction_update, thatch_prediction_list,
24
+ thatch_prediction_delete,
25
+ thatch_behavior_codify, thatch_behavior_feedback, thatch_behavior_list,
26
+ thatch_behavior_delete, thatch_get_session_info,
27
+ thatch_session_search, thatch_session_get,
28
+ thatch_watch_create, thatch_watch_list, thatch_watch_cancel
27
29
 
28
30
  ## Stores
29
31
 
@@ -107,6 +109,20 @@ the same prompt. If the re-dispatch also fails or times out, note the gap and
107
109
  move on. Do not retry more than once - repeated failures indicate an
108
110
  intractable prompt, not a transient hang.
109
111
 
112
+ ## Watchers
113
+
114
+ Use thatch_watch_create to watch a GitHub PR for events (comments, review
115
+ comments and replies, commits, status changes, description edits, CI check
116
+ completions). thatch polls the PR in the background and injects a
117
+ notification into this session when a watched event happens. The
118
+ notification carries pointer data only (author, URL); fetch details with
119
+ the gh CLI when you decide to act. When the user asks you to watch
120
+ something, state your handling policy for notifications out loud first
121
+ ("I'll report human comments and handle bugbot replies myself") so the
122
+ notification turn knows what to do. Treat watcher notifications like
123
+ background task completions: they are system events, not user input, and
124
+ not approval to advance other pending work.
125
+
110
126
  ## User Decision Model
111
127
 
112
128
  A statistical model of the user's decision-making preferences is maintained by
@@ -270,6 +286,10 @@ Tools are prefixed in ${host}: \`mcp__thatch__memory_remember\`,
270
286
  \`mcp__thatch__prediction_list\`, \`mcp__thatch__prediction_delete\`,
271
287
  \`mcp__thatch__behavior_codify\`, \`mcp__thatch__behavior_feedback\`,
272
288
  \`mcp__thatch__behavior_list\`, \`mcp__thatch__behavior_delete\`. Bare names used below for readability.
289
+ get_session_info, session_search, session_get, watch_create, watch_list,
290
+ and watch_cancel are intentionally absent: they are opencode-only (MCP
291
+ hosts have no session concept, session database, or proactive-prompt
292
+ channel), so do not expect them here.
273
293
 
274
294
  ## Stores
275
295
 
@@ -668,3 +688,19 @@ export function behaviorNudge(items: BehaviorNudgeItem[]): string {
668
688
  });
669
689
  return `[thatch] Situational behaviors\n${lines.join("\n")}`;
670
690
  }
691
+
692
+ /**
693
+ * Watcher notification for the poller's promptAsync delivery. Injected as a
694
+ * synthetic part that triggers a model turn. Events carry pointer data only
695
+ * (author, URL) - never external content - so the model fetches details on
696
+ * demand with the gh CLI. The wrapper text borrows the background-task
697
+ * completion framing: a system event, not user input, not approval to
698
+ * advance other pending work.
699
+ */
700
+ export function watcherNotificationNudge(target: string, events: { type: string; summary: string; url: string }[]): string {
701
+ const lines = events.map((e) => `- ${e.type}: ${e.summary} ${e.url}`);
702
+ return `[thatch] Watcher notification for ${target}
703
+ ${lines.join("\n")}
704
+
705
+ This is a system notification, not user input. Decide whether to act now or keep waiting - the user's instructions from when the watch was created govern how to handle it. Fetch details with the gh CLI if you need them. Do not treat this notification as approval to advance other pending work. If you act, tell the user what you did and why; if not, stop and wait.`;
706
+ }