harnex 0.6.0 → 0.6.3

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.
@@ -0,0 +1,94 @@
1
+ # Buddy Monitoring
2
+
3
+ A buddy is a second harnex session that watches one or more workers and nudges
4
+ them if they stall. Use a buddy when the work is long-running, unattended, or
5
+ needs interpretation that simple stall policy cannot provide.
6
+
7
+ For simple inactivity recovery, prefer built-in watch mode:
8
+
9
+ ```bash
10
+ harnex run codex --id cx-i-NN --watch --preset impl --context "Read /tmp/task-impl-NN.md"
11
+ ```
12
+
13
+ Use a buddy when you need reasoning over pane contents, semantic checks, or
14
+ multi-session correlation.
15
+
16
+ ## When To Use
17
+
18
+ Use a buddy for:
19
+
20
+ - Overnight or multi-hour work.
21
+ - Any dispatched task expected to run more than about 30 minutes unattended.
22
+ - Work where a stalled prompt, permission request, or disconnect would waste a
23
+ long slot.
24
+ - Monitoring multiple signals before deciding whether to nudge.
25
+
26
+ ## Spawn
27
+
28
+ Spawn the worker first, then spawn the buddy:
29
+
30
+ ```bash
31
+ harnex run codex --id cx-i-42 --tmux cx-i-42 \
32
+ --context "Read and execute /tmp/task-impl-42.md"
33
+
34
+ harnex run claude --id buddy-42 --tmux buddy-42
35
+ ```
36
+
37
+ The buddy is just another harnex session. Inspect it, stop it, and read its
38
+ logs with the same commands as any worker.
39
+
40
+ ## Buddy Prompt
41
+
42
+ Give the buddy an explicit polling loop, stall threshold, nudge rule, return
43
+ channel, and cleanup rule:
44
+
45
+ ```text
46
+ You are an accountability partner for harnex session `cx-i-42`.
47
+
48
+ Every 5 minutes:
49
+ - Run `harnex pane --id cx-i-42 --lines 30`.
50
+ - Run `harnex status --id cx-i-42 --json`.
51
+
52
+ If the worker appears stuck at a prompt or permission dialog for more than
53
+ 10 minutes with no progress, nudge it:
54
+ - `harnex send --id cx-i-42 --message "You appear to have stalled. Continue with your current task."`
55
+
56
+ If the worker exits or writes `/tmp/cx-i-42-done.txt`, report back:
57
+ - `tmux send-keys -t "$HARNEX_SPAWNER_PANE" "cx-i-42 finished. Check /tmp/cx-i-42-done.txt." Enter`
58
+
59
+ Do not interfere with active work. Stop yourself after reporting completion.
60
+ ```
61
+
62
+ Send it:
63
+
64
+ ```bash
65
+ harnex send --id buddy-42 --message "Read and execute /tmp/buddy-42.md"
66
+ ```
67
+
68
+ ## Return Channel
69
+
70
+ Every harnex-spawned session receives `HARNEX_SPAWNER_PANE` when the invoker is
71
+ inside tmux. The buddy can use it to report to an invoker that is not itself a
72
+ harnex session:
73
+
74
+ ```bash
75
+ tmux capture-pane -t "$HARNEX_SPAWNER_PANE" -p
76
+ tmux send-keys -t "$HARNEX_SPAWNER_PANE" "cx-i-42 finished" Enter
77
+ ```
78
+
79
+ If no tmux return pane is available, require the buddy to write a file and tell
80
+ the invoker where to read it.
81
+
82
+ ## Cleanup
83
+
84
+ Stop the buddy after the worker completes:
85
+
86
+ ```bash
87
+ harnex stop --id buddy-42
88
+ ```
89
+
90
+ For full recipe form, use:
91
+
92
+ ```bash
93
+ harnex recipes show 03
94
+ ```
@@ -0,0 +1,130 @@
1
+ # Monitoring Patterns
2
+
3
+ Monitoring should be based on work-level signals first and UI state second.
4
+ Pane state is useful for interpretation, but it should not be the only proof
5
+ that delegated work is finished.
6
+
7
+ ## Signal Ladder
8
+
9
+ Prefer signals in this order:
10
+
11
+ | Signal | Use |
12
+ | --- | --- |
13
+ | Expected artifact | Primary proof that a task produced its deliverable |
14
+ | Tests and git state | Confirms work landed and the tree is not mid-edit |
15
+ | `harnex events` | Structured runtime events, including task completion |
16
+ | `harnex logs` | Transcript history and last output |
17
+ | `harnex pane` | Live UI interpretation and prompt/error diagnosis |
18
+ | `harnex status` | Session liveness and coarse state |
19
+
20
+ For Codex app-server sessions, `harnex wait --until task_complete` is a strong
21
+ turn-level fence. It still does not know your acceptance criteria; verify the
22
+ expected artifact or tests afterward.
23
+
24
+ ## Completion Test
25
+
26
+ For unattended work, declare done with a conjunction of work-level facts:
27
+
28
+ ```bash
29
+ test -f /tmp/cx-i-NN-done.txt &&
30
+ test -z "$(git status --short)" &&
31
+ test "$(git log -1 --format=%ct)" -lt "$(($(date +%s) - 600))"
32
+ ```
33
+
34
+ Adjust the artifact path and commit-age window to the task. The point is to
35
+ avoid declaring done while a worker is between edits or between commits.
36
+
37
+ ## Why Pane State Alone Is Not Enough
38
+
39
+ Avoid using `state=prompt` or a quiet pane as the only completion signal:
40
+
41
+ - A finished agent can sit at a prompt forever.
42
+ - Some CLIs stay in a session state while auto-fix or tool loops continue.
43
+ - Focus changes and UI redraws can reset idle timers.
44
+ - A prompt can also mean the agent is blocked, not done.
45
+
46
+ Use `harnex pane` to understand what happened after a stronger signal tells you
47
+ where to look.
48
+
49
+ ## Polling Patterns
50
+
51
+ For active supervision:
52
+
53
+ ```bash
54
+ harnex pane --id cx-i-NN --lines 40
55
+ harnex events --id cx-i-NN --snapshot
56
+ harnex logs --id cx-i-NN --lines 80
57
+ ```
58
+
59
+ For continuous viewing:
60
+
61
+ ```bash
62
+ harnex pane --id cx-i-NN --follow --interval 2
63
+ harnex logs --id cx-i-NN --follow
64
+ harnex events --id cx-i-NN
65
+ ```
66
+
67
+ For task completion:
68
+
69
+ ```bash
70
+ harnex wait --id cx-i-NN --until task_complete --timeout 900
71
+ ```
72
+
73
+ ## Background Sweeper
74
+
75
+ Consumers often run a small shell loop that checks the expected done marker,
76
+ tree state, and harnex liveness. Keep a hard wall-clock cap so an unattended
77
+ pipeline cannot wait forever:
78
+
79
+ ```bash
80
+ start=$(date +%s)
81
+ max_wait=5400
82
+
83
+ until test -f /tmp/cx-i-NN-done.txt; do
84
+ if test "$(($(date +%s) - start))" -gt "$max_wait"; then
85
+ echo "wall-clock cap hit for cx-i-NN" >&2
86
+ exit 2
87
+ fi
88
+
89
+ harnex status --id cx-i-NN --json
90
+ harnex pane --id cx-i-NN --lines 20
91
+ sleep 60
92
+ done
93
+ ```
94
+
95
+ Recommended caps:
96
+
97
+ | Work type | Cap |
98
+ | --- | --- |
99
+ | Small single dispatch | 30 minutes |
100
+ | Medium implementation | 90 minutes |
101
+ | Large unattended phase | 3 hours |
102
+
103
+ ## Built-In Watch Mode
104
+
105
+ Use `harnex run --watch` when one foreground process should launch the worker
106
+ and apply bounded stall recovery:
107
+
108
+ ```bash
109
+ harnex run codex --id cx-i-NN --watch --preset impl \
110
+ --context "Read /tmp/task-impl-NN.md"
111
+ ```
112
+
113
+ `--watch` exits with:
114
+
115
+ | Code | Meaning |
116
+ | --- | --- |
117
+ | `0` | Session exited |
118
+ | `1` | Operational error |
119
+ | `2` | Watcher escalated after bounded resumes |
120
+
121
+ Use a buddy instead when the monitoring decision needs language-level
122
+ interpretation.
123
+
124
+ ## Anti-Patterns
125
+
126
+ - Polling `state=prompt` alone and calling it done.
127
+ - Letting an unattended loop run with no wall-clock cap.
128
+ - Reading raw tmux panes instead of `harnex pane`.
129
+ - Using `--wait-for-idle` as acceptance proof.
130
+ - Reusing a worker after a failure changes the task scope.
@@ -0,0 +1,106 @@
1
+ # Naming Conventions
2
+
3
+ Use predictable session IDs so humans, agents, tmux windows, logs, events, and
4
+ done markers all point at the same work.
5
+
6
+ ## Session IDs
7
+
8
+ Format:
9
+
10
+ ```text
11
+ <cli>-<phase>-<number>
12
+ ```
13
+
14
+ Common prefixes:
15
+
16
+ | Prefix | Meaning |
17
+ | --- | --- |
18
+ | `cx` | Codex worker |
19
+ | `cl` | Claude worker |
20
+ | `buddy` | Buddy monitor |
21
+
22
+ Common phases:
23
+
24
+ | Code | Phase |
25
+ | --- | --- |
26
+ | `m` | Mapping or analysis |
27
+ | `p` | Plan writing |
28
+ | `r` | Plan review |
29
+ | `f` | Plan fix |
30
+ | `i` | Implementation |
31
+ | `cr` | Code review |
32
+ | `cf` | Code fix |
33
+
34
+ Examples:
35
+
36
+ ```text
37
+ cx-m-42 Codex maps task 42
38
+ cx-p-42 Codex writes plan 42
39
+ cx-r-42 Codex reviews plan 42
40
+ cx-f-42 Codex fixes plan 42
41
+ cx-i-42 Codex implements plan 42
42
+ cx-cr-42 Codex reviews implementation 42
43
+ cx-cf-42 Codex fixes implementation 42
44
+ buddy-42 Buddy monitors task 42
45
+ ```
46
+
47
+ Use names that fit your project. The important part is that the ID is stable,
48
+ short, and present in every artifact.
49
+
50
+ ## Match `--id` And `--tmux`
51
+
52
+ Always pass both and keep them identical:
53
+
54
+ ```bash
55
+ harnex run codex --id cx-i-42 --tmux cx-i-42
56
+ ```
57
+
58
+ Avoid this:
59
+
60
+ ```bash
61
+ harnex run codex --tmux cx-i-42
62
+ ```
63
+
64
+ If `--id` is missing, harnex generates a random session ID. The tmux window may
65
+ look right, but `harnex status`, `harnex pane --id`, and logs need the random
66
+ ID.
67
+
68
+ ## Retry Suffixes
69
+
70
+ If a session fails and you dispatch a fresh attempt, append a suffix:
71
+
72
+ ```text
73
+ cx-i-42 first attempt
74
+ cx-i-42b second attempt
75
+ cx-i-42c third attempt
76
+ ```
77
+
78
+ Keep the old session's logs. They are useful for diagnosis.
79
+
80
+ ## Task Files
81
+
82
+ Use human-readable file names for long instructions:
83
+
84
+ ```text
85
+ /tmp/task-plan-42.md
86
+ /tmp/task-impl-42.md
87
+ /tmp/task-review-42.md
88
+ /tmp/task-fix-42.md
89
+ ```
90
+
91
+ The task file name does not need to duplicate the exact short phase code. It
92
+ should be easy to scan in `/tmp` and should include the same task number as the
93
+ session ID.
94
+
95
+ ## Done Markers
96
+
97
+ Derive done markers from the session ID:
98
+
99
+ ```text
100
+ /tmp/cx-p-42-done.txt
101
+ /tmp/cx-i-42-done.txt
102
+ /tmp/cx-cr-42-done.txt
103
+ ```
104
+
105
+ When a brief asks for a completion marker, make it one line and include the
106
+ highest-signal result: tests passed, review clean, or the blocking issue.
@@ -34,10 +34,11 @@ module Harnex
34
34
 
35
35
  EVENTS = %w[task_complete turn_started item_completed disconnected].freeze
36
36
 
37
- attr_reader :thread_id, :current_turn_id, :last_completed_at
37
+ attr_reader :thread_id, :current_turn_id, :last_completed_at, :initial_prompt
38
38
 
39
39
  def initialize(extra_args = [])
40
40
  super("codex", extra_args)
41
+ @initial_prompt = extract_initial_prompt(extra_args)
41
42
  @client = nil
42
43
  @thread_id = nil
43
44
  @current_turn_id = nil
@@ -55,6 +56,10 @@ module Harnex
55
56
  ["codex", "app-server"]
56
57
  end
57
58
 
59
+ def build_command
60
+ base_command
61
+ end
62
+
58
63
  def describe
59
64
  {
60
65
  transport: transport,
@@ -76,10 +81,19 @@ module Harnex
76
81
  }
77
82
  end
78
83
 
79
- # The screen-based send path is not used for stdio_jsonrpc.
80
- # Session#run_jsonrpc routes through #dispatch instead.
81
- def build_send_payload(*)
82
- raise NotImplementedError, "codex_appserver uses #dispatch, not screen-based send"
84
+ def build_send_payload(text:, submit:, enter_only:, screen_text:, force: false)
85
+ state = input_state(nil)
86
+ if !force && submit && !enter_only && state[:input_ready] != true
87
+ raise ArgumentError, blocked_message(state, enter_only: enter_only)
88
+ end
89
+ raise ArgumentError, "Codex app-server cannot stage input without submitting it" unless submit || enter_only
90
+ raise ArgumentError, "Codex app-server does not support submit-only input" if enter_only
91
+
92
+ {
93
+ dispatch: { prompt: text.to_s },
94
+ input_state: state,
95
+ force: force
96
+ }
83
97
  end
84
98
 
85
99
  # No-op: closing the subprocess is handled via #close.
@@ -118,7 +132,7 @@ module Harnex
118
132
  ensure_thread!
119
133
  params = {
120
134
  threadId: @thread_id,
121
- input: { content: [{ type: "text", text: prompt.to_s }] }
135
+ input: [{ type: "text", text: prompt.to_s }]
122
136
  }
123
137
  params[:model] = model if model
124
138
  params[:effort] = effort if effort
@@ -168,7 +182,22 @@ module Harnex
168
182
  return if @thread_id
169
183
 
170
184
  result = @client.request("thread/start", {})
171
- @thread_id = result["threadId"] || result["thread_id"]
185
+ @thread_id = extract_thread_id(result)
186
+ end
187
+
188
+ def extract_thread_id(payload)
189
+ return nil unless payload.is_a?(Hash)
190
+
191
+ payload.dig("thread", "id") || payload["threadId"] || payload["thread_id"]
192
+ end
193
+
194
+ def extract_initial_prompt(extra_args)
195
+ return nil unless extra_args.is_a?(Array)
196
+
197
+ prefixed = extra_args.find { |a| a.is_a?(String) && a.start_with?("[harnex session id=") }
198
+ return prefixed if prefixed && !prefixed.empty?
199
+
200
+ nil
172
201
  end
173
202
 
174
203
  def perform_handshake
@@ -192,7 +221,7 @@ module Harnex
192
221
 
193
222
  case method
194
223
  when "thread/started"
195
- @thread_id ||= params["threadId"] || params["thread_id"]
224
+ @thread_id ||= extract_thread_id(params)
196
225
  when "turn/started"
197
226
  @current_turn_id = params["turnId"] || params["turn_id"]
198
227
  @state = :busy
@@ -221,6 +250,12 @@ module Harnex
221
250
  [wait_thr.pid, stdin_io, stdout_io]
222
251
  end
223
252
 
253
+ def blocked_message(state, enter_only:)
254
+ return super if enter_only
255
+
256
+ "Codex app-server is not at a prompt; wait and retry or use `harnex send --force` (state: #{state[:state]})"
257
+ end
258
+
224
259
  # Minimal JSON-RPC 2.0 client. One JSON object per line.
225
260
  # Responses keyed by id; everything else is a notification.
226
261
  class JsonRpcClient
data/lib/harnex/cli.rb CHANGED
@@ -29,8 +29,8 @@ module Harnex
29
29
  Recipes.new(@argv.drop(1)).run
30
30
  when "guide"
31
31
  Guide.new.run
32
- when "skills"
33
- Skills.new(@argv.drop(1)).run
32
+ when "agents-guide"
33
+ AgentsGuide.new(@argv.drop(1)).run
34
34
  when "doctor"
35
35
  Doctor.new(@argv.drop(1)).run
36
36
  when "help"
@@ -71,8 +71,10 @@ module Harnex
71
71
  Recipes.usage
72
72
  when "guide"
73
73
  Guide.usage
74
- when "skills"
75
- Skills.usage
74
+ when "agents-guide"
75
+ AgentsGuide.usage
76
+ when "doctor"
77
+ Doctor.usage
76
78
  else
77
79
  usage
78
80
  end
@@ -89,6 +91,8 @@ module Harnex
89
91
  harnex logs --id ID [options]
90
92
  harnex events --id ID [options]
91
93
  harnex pane --id ID [options]
94
+ harnex agents-guide [topic]
95
+ harnex doctor
92
96
  harnex help [command]
93
97
 
94
98
  Commands:
@@ -102,11 +106,13 @@ module Harnex
102
106
  pane Capture the current tmux pane for a live session
103
107
  recipes List and read workflow recipes
104
108
  guide Show the getting started guide
105
- skills Install bundled skills into a repo or globally
109
+ agents-guide
110
+ Show agent dispatch, chain, buddy, monitoring, and naming guides
106
111
  doctor Run preflight checks for adapter dependencies
107
112
  help Show command help
108
113
 
109
114
  New to harnex? Start with: harnex guide
115
+ Working with agents (dispatching tasks)? Read: harnex agents-guide
110
116
 
111
117
  Notes:
112
118
  CLIs with smart prompt detection: #{Adapters.known.join(', ')}
@@ -120,8 +126,9 @@ module Harnex
120
126
  harnex logs --id main --follow
121
127
  harnex events --id main --snapshot
122
128
  harnex pane --id main --lines 40
129
+ harnex agents-guide dispatch
130
+ harnex doctor
123
131
  harnex send --id main --message "Summarize current progress."
124
- harnex skills install
125
132
  TEXT
126
133
  end
127
134
  end
@@ -0,0 +1,109 @@
1
+ module Harnex
2
+ class AgentsGuide
3
+ GUIDES_DIR = File.expand_path("../../../../guides", __FILE__)
4
+
5
+ def self.usage
6
+ <<~TEXT
7
+ Usage: harnex agents-guide [list|show <topic>|<topic>]
8
+
9
+ Subcommands:
10
+ list List available agent guide topics (default)
11
+ show <topic> Print a guide by name or number
12
+
13
+ Examples:
14
+ harnex agents-guide
15
+ harnex agents-guide list
16
+ harnex agents-guide show 01
17
+ harnex agents-guide show dispatch
18
+ harnex agents-guide monitoring
19
+
20
+ Common patterns:
21
+ harnex agents-guide dispatch
22
+ harnex agents-guide chain
23
+ harnex agents-guide naming
24
+
25
+ Gotchas:
26
+ Agent guides replace the old harnex skills install flow.
27
+ They are packaged with the gem and require no external project docs.
28
+ TEXT
29
+ end
30
+
31
+ def initialize(argv)
32
+ @argv = argv.dup
33
+ end
34
+
35
+ def run
36
+ subcommand = @argv.shift
37
+ case subcommand
38
+ when nil, "list"
39
+ list_guides
40
+ when "show"
41
+ show_guide(@argv.first)
42
+ when "-h", "--help"
43
+ puts self.class.usage
44
+ 0
45
+ else
46
+ show_guide(subcommand)
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def list_guides
53
+ files = guide_files
54
+ if files.empty?
55
+ puts "No agent guides found."
56
+ return 0
57
+ end
58
+
59
+ puts "Agent guides:\n\n"
60
+ files.each do |file|
61
+ name = File.basename(file, ".md")
62
+ title = extract_title(file)
63
+ puts " #{name} #{title}"
64
+ end
65
+ puts "\nRun `harnex agents-guide show <topic>` to read one."
66
+ 0
67
+ end
68
+
69
+ def show_guide(query)
70
+ unless query
71
+ warn("harnex agents-guide show: topic required")
72
+ return 1
73
+ end
74
+
75
+ file = find_guide(query)
76
+ unless file
77
+ warn("harnex agents-guide: no topic matching #{query.inspect}")
78
+ warn("Run `harnex agents-guide list` to see available topics.")
79
+ return 1
80
+ end
81
+
82
+ puts File.read(file)
83
+ 0
84
+ end
85
+
86
+ def find_guide(query)
87
+ files = guide_files
88
+
89
+ exact = files.find { |file| File.basename(file, ".md") == query }
90
+ return exact if exact
91
+
92
+ prefix = files.find { |file| File.basename(file, ".md").start_with?(query) }
93
+ return prefix if prefix
94
+
95
+ files.find { |file| File.basename(file, ".md").include?(query) }
96
+ end
97
+
98
+ def guide_files
99
+ return [] unless Dir.exist?(GUIDES_DIR)
100
+
101
+ Dir.glob(File.join(GUIDES_DIR, "*.md")).sort
102
+ end
103
+
104
+ def extract_title(file)
105
+ first_line = File.foreach(file).first.to_s.strip
106
+ first_line.start_with?("#") ? first_line.sub(/^#+\s*/, "") : ""
107
+ end
108
+ end
109
+ end
@@ -12,6 +12,14 @@ module Harnex
12
12
  Currently verifies that Codex CLI is installed and at version
13
13
  >= #{MIN_CODEX_VERSION} (required for the JSON-RPC `app-server`
14
14
  adapter).
15
+
16
+ Common patterns:
17
+ harnex doctor
18
+ harnex doctor --help
19
+
20
+ Gotchas:
21
+ doctor validates local adapter prerequisites; it does not start sessions.
22
+ Run it after installing or upgrading Codex CLI.
15
23
  TEXT
16
24
  end
17
25
 
@@ -18,6 +18,16 @@ module Harnex
18
18
  --snapshot Print current events and exit (alias for --no-follow)
19
19
  --from TS Replay floor (ISO-8601, inclusive)
20
20
  -h, --help Show this help
21
+
22
+ Common patterns:
23
+ #{program_name} --id cx-i-42 --snapshot
24
+ #{program_name} --id cx-i-42
25
+ #{program_name} --id cx-i-42 --from 2026-05-06T10:00:00Z --snapshot
26
+
27
+ Gotchas:
28
+ events is structured JSONL; logs is human transcript text.
29
+ Default mode follows live events. Use --snapshot to print and exit.
30
+ Use wait --until task_complete when you only need a completion fence.
21
31
  TEXT
22
32
  end
23
33
 
@@ -7,6 +7,15 @@ module Harnex
7
7
  Usage: harnex guide
8
8
 
9
9
  Print the getting started guide.
10
+
11
+ Common patterns:
12
+ harnex guide
13
+ harnex agents-guide
14
+ harnex recipes
15
+
16
+ Gotchas:
17
+ guide is short human onboarding.
18
+ agents-guide is the deeper operational reference for dispatching agents.
10
19
  TEXT
11
20
  end
12
21
 
@@ -17,6 +17,16 @@ module Harnex
17
17
  --follow Keep streaming appended output until session exit
18
18
  --lines N Print the last N lines before following (default: #{DEFAULT_LINES})
19
19
  -h, --help Show this help
20
+
21
+ Common patterns:
22
+ #{program_name} --id cx-i-42 --lines 80
23
+ #{program_name} --id cx-i-42 --follow
24
+ #{program_name} --id cx-i-42 --repo /path/to/repo --lines 200
25
+
26
+ Gotchas:
27
+ logs reads the persisted transcript, not the live tmux screen.
28
+ Use pane when you need the current TUI view or prompt text.
29
+ --follow streams until the live session exits.
20
30
  TEXT
21
31
  end
22
32
 
@@ -20,6 +20,16 @@ module Harnex
20
20
  --interval N Refresh interval in seconds for --follow (default: #{FOLLOW_INTERVAL.to_i})
21
21
  --json Output JSON with capture metadata
22
22
  -h, --help Show this help
23
+
24
+ Common patterns:
25
+ #{program_name} --id cx-i-42 --lines 40
26
+ #{program_name} --id cx-i-42 --lines 40 --json
27
+ #{program_name} --id cx-i-42 --follow --interval 2
28
+
29
+ Gotchas:
30
+ pane requires a tmux-backed session.
31
+ Use --repo when the same ID exists in multiple repos or worktrees.
32
+ Do not use pane state alone as completion proof; verify artifacts/tests.
23
33
  TEXT
24
34
  end
25
35
 
@@ -17,6 +17,15 @@ module Harnex
17
17
  harnex recipes list
18
18
  harnex recipes show 01
19
19
  harnex recipes show fire_and_watch
20
+
21
+ Common patterns:
22
+ harnex recipes show 01 # Fire and Watch
23
+ harnex recipes show 02 # Chain Implement
24
+ harnex recipes show 03 # Buddy
25
+
26
+ Gotchas:
27
+ Recipes are compact command walkthroughs.
28
+ Use `harnex agents-guide` for the deeper agent-facing guide.
20
29
  TEXT
21
30
  end
22
31