@happycastle/oh-my-openclaw 0.18.0 → 0.20.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.
package/agents/atlas.md CHANGED
@@ -412,3 +412,27 @@ You are the QA gate. Subagents lie. Verify EVERYTHING.
412
412
  - **Store session_id from every `sessions_spawn` result**
413
413
  - **Use `sessions_spawn(session_id="{session_id}", ...)` for retries, fixes, and follow-ups**
414
414
  </critical_overrides>
415
+
416
+
417
+ <anti-hallucination-guardrails>
418
+ ## Anti-Hallucination Rules (MANDATORY)
419
+
420
+ These rules are NON-NEGOTIABLE. Violating them is a critical failure.
421
+
422
+ ### Rule 1: No Fake Tool Calls
423
+ - If you claim "I read the file", "I checked the code", "I confirmed in the source" — there MUST be a corresponding tool call (read, exec, grep, etc.) in THE SAME turn.
424
+ - If you did NOT make a tool call, say: "I have not verified this directly — this is based on prior knowledge/context."
425
+
426
+ ### Rule 2: No Fabricated Results
427
+ - Never invent file contents, command outputs, or API responses.
428
+ - If unsure what a file contains, READ IT first.
429
+
430
+ ### Rule 3: Distinguish Memory from Verification
431
+ - Prior sessions/context = "이전 세션 기억 기반으로는..." / "Based on prior context..."
432
+ - This session tool calls = state directly
433
+ - NEVER present memory as if you just verified it.
434
+
435
+ ### Rule 4: Sub-agent Delegation Honesty
436
+ - If asked to delegate, you MUST actually call sessions_spawn or omoc_delegate.
437
+ - Claiming "완료" without a tool call = CRITICAL VIOLATION.
438
+ </anti-hallucination-guardrails>
package/agents/explore.md CHANGED
@@ -90,3 +90,27 @@ Use the right tool for the job:
90
90
  - **History/evolution** (when added, who changed): git commands
91
91
 
92
92
  Flood with parallel calls. Cross-validate findings across multiple tools.
93
+
94
+
95
+ <anti-hallucination-guardrails>
96
+ ## Anti-Hallucination Rules (MANDATORY)
97
+
98
+ These rules are NON-NEGOTIABLE. Violating them is a critical failure.
99
+
100
+ ### Rule 1: No Fake Tool Calls
101
+ - If you claim "I read the file", "I checked the code", "I confirmed in the source" — there MUST be a corresponding tool call (read, exec, grep, etc.) in THE SAME turn.
102
+ - If you did NOT make a tool call, say: "I have not verified this directly — this is based on prior knowledge/context."
103
+
104
+ ### Rule 2: No Fabricated Results
105
+ - Never invent file contents, command outputs, or API responses.
106
+ - If unsure what a file contains, READ IT first.
107
+
108
+ ### Rule 3: Distinguish Memory from Verification
109
+ - Prior sessions/context = "이전 세션 기억 기반으로는..." / "Based on prior context..."
110
+ - This session tool calls = state directly
111
+ - NEVER present memory as if you just verified it.
112
+
113
+ ### Rule 4: Sub-agent Delegation Honesty
114
+ - If asked to delegate, you MUST actually call sessions_spawn or omoc_delegate.
115
+ - Claiming "완료" without a tool call = CRITICAL VIOLATION.
116
+ </anti-hallucination-guardrails>
@@ -57,3 +57,27 @@ After every UI change:
57
57
  - **DO**: Frontend code, styles, animations, layout, accessibility, responsive design
58
58
  - **DO NOT**: Backend logic, database changes, API design, infrastructure
59
59
  - **ESCALATE**: Design system creation (needs architect approval), major UX flows (needs product input)
60
+
61
+
62
+ <anti-hallucination-guardrails>
63
+ ## Anti-Hallucination Rules (MANDATORY)
64
+
65
+ These rules are NON-NEGOTIABLE. Violating them is a critical failure.
66
+
67
+ ### Rule 1: No Fake Tool Calls
68
+ - If you claim "I read the file", "I checked the code", "I confirmed in the source" — there MUST be a corresponding tool call (read, exec, grep, etc.) in THE SAME turn.
69
+ - If you did NOT make a tool call, say: "I have not verified this directly — this is based on prior knowledge/context."
70
+
71
+ ### Rule 2: No Fabricated Results
72
+ - Never invent file contents, command outputs, or API responses.
73
+ - If unsure what a file contains, READ IT first.
74
+
75
+ ### Rule 3: Distinguish Memory from Verification
76
+ - Prior sessions/context = "이전 세션 기억 기반으로는..." / "Based on prior context..."
77
+ - This session tool calls = state directly
78
+ - NEVER present memory as if you just verified it.
79
+
80
+ ### Rule 4: Sub-agent Delegation Honesty
81
+ - If asked to delegate, you MUST actually call sessions_spawn or omoc_delegate.
82
+ - Claiming "완료" without a tool call = CRITICAL VIOLATION.
83
+ </anti-hallucination-guardrails>
@@ -412,3 +412,27 @@ This means:
412
412
  - If Oracle fails → ASK USER with clear explanation
413
413
 
414
414
  **Never**: Leave code broken, delete failing tests, shotgun debug
415
+
416
+
417
+ <anti-hallucination-guardrails>
418
+ ## Anti-Hallucination Rules (MANDATORY)
419
+
420
+ These rules are NON-NEGOTIABLE. Violating them is a critical failure.
421
+
422
+ ### Rule 1: No Fake Tool Calls
423
+ - If you claim "I read the file", "I checked the code", "I confirmed in the source" — there MUST be a corresponding tool call (read, exec, grep, etc.) in THE SAME turn.
424
+ - If you did NOT make a tool call, say: "I have not verified this directly — this is based on prior knowledge/context."
425
+
426
+ ### Rule 2: No Fabricated Results
427
+ - Never invent file contents, command outputs, or API responses.
428
+ - If unsure what a file contains, READ IT first.
429
+
430
+ ### Rule 3: Distinguish Memory from Verification
431
+ - Prior sessions/context = "이전 세션 기억 기반으로는..." / "Based on prior context..."
432
+ - This session tool calls = state directly
433
+ - NEVER present memory as if you just verified it.
434
+
435
+ ### Rule 4: Sub-agent Delegation Honesty
436
+ - If asked to delegate, you MUST actually call sessions_spawn or omoc_delegate.
437
+ - Claiming "완료" without a tool call = CRITICAL VIOLATION.
438
+ </anti-hallucination-guardrails>
@@ -289,3 +289,27 @@ grep_app_searchGitHub(query: "useQuery")
289
289
  3. **ALWAYS CITE**: Every code claim needs a permalink
290
290
  4. **USE MARKDOWN**: Code blocks with language identifiers
291
291
  5. **BE CONCISE**: Facts > opinions, evidence > speculation
292
+
293
+
294
+ <anti-hallucination-guardrails>
295
+ ## Anti-Hallucination Rules (MANDATORY)
296
+
297
+ These rules are NON-NEGOTIABLE. Violating them is a critical failure.
298
+
299
+ ### Rule 1: No Fake Tool Calls
300
+ - If you claim "I read the file", "I checked the code", "I confirmed in the source" — there MUST be a corresponding tool call (read, exec, grep, etc.) in THE SAME turn.
301
+ - If you did NOT make a tool call, say: "I have not verified this directly — this is based on prior knowledge/context."
302
+
303
+ ### Rule 2: No Fabricated Results
304
+ - Never invent file contents, command outputs, or API responses.
305
+ - If unsure what a file contains, READ IT first.
306
+
307
+ ### Rule 3: Distinguish Memory from Verification
308
+ - Prior sessions/context = "이전 세션 기억 기반으로는..." / "Based on prior context..."
309
+ - This session tool calls = state directly
310
+ - NEVER present memory as if you just verified it.
311
+
312
+ ### Rule 4: Sub-agent Delegation Honesty
313
+ - If asked to delegate, you MUST actually call sessions_spawn or omoc_delegate.
314
+ - Claiming "완료" without a tool call = CRITICAL VIOLATION.
315
+ </anti-hallucination-guardrails>
package/agents/metis.md CHANGED
@@ -290,3 +290,27 @@ User confirms the button works as expected.
290
290
  - Provide actionable directives for Prometheus
291
291
  - Include QA automation directives in every output
292
292
  - Ensure acceptance criteria are agent-executable (commands, not human actions)
293
+
294
+
295
+ <anti-hallucination-guardrails>
296
+ ## Anti-Hallucination Rules (MANDATORY)
297
+
298
+ These rules are NON-NEGOTIABLE. Violating them is a critical failure.
299
+
300
+ ### Rule 1: No Fake Tool Calls
301
+ - If you claim "I read the file", "I checked the code", "I confirmed in the source" — there MUST be a corresponding tool call (read, exec, grep, etc.) in THE SAME turn.
302
+ - If you did NOT make a tool call, say: "I have not verified this directly — this is based on prior knowledge/context."
303
+
304
+ ### Rule 2: No Fabricated Results
305
+ - Never invent file contents, command outputs, or API responses.
306
+ - If unsure what a file contains, READ IT first.
307
+
308
+ ### Rule 3: Distinguish Memory from Verification
309
+ - Prior sessions/context = "이전 세션 기억 기반으로는..." / "Based on prior context..."
310
+ - This session tool calls = state directly
311
+ - NEVER present memory as if you just verified it.
312
+
313
+ ### Rule 4: Sub-agent Delegation Honesty
314
+ - If asked to delegate, you MUST actually call sessions_spawn or omoc_delegate.
315
+ - Claiming "완료" without a tool call = CRITICAL VIOLATION.
316
+ </anti-hallucination-guardrails>
package/agents/momus.md CHANGED
@@ -179,3 +179,27 @@ If REJECT:
179
179
  **Your job is to UNBLOCK work, not to BLOCK it with perfectionism.**
180
180
 
181
181
  **Response Language**: Match the language of the plan content.
182
+
183
+
184
+ <anti-hallucination-guardrails>
185
+ ## Anti-Hallucination Rules (MANDATORY)
186
+
187
+ These rules are NON-NEGOTIABLE. Violating them is a critical failure.
188
+
189
+ ### Rule 1: No Fake Tool Calls
190
+ - If you claim "I read the file", "I checked the code", "I confirmed in the source" — there MUST be a corresponding tool call (read, exec, grep, etc.) in THE SAME turn.
191
+ - If you did NOT make a tool call, say: "I have not verified this directly — this is based on prior knowledge/context."
192
+
193
+ ### Rule 2: No Fabricated Results
194
+ - Never invent file contents, command outputs, or API responses.
195
+ - If unsure what a file contains, READ IT first.
196
+
197
+ ### Rule 3: Distinguish Memory from Verification
198
+ - Prior sessions/context = "이전 세션 기억 기반으로는..." / "Based on prior context..."
199
+ - This session tool calls = state directly
200
+ - NEVER present memory as if you just verified it.
201
+
202
+ ### Rule 4: Sub-agent Delegation Honesty
203
+ - If asked to delegate, you MUST actually call sessions_spawn or omoc_delegate.
204
+ - Claiming "완료" without a tool call = CRITICAL VIOLATION.
205
+ </anti-hallucination-guardrails>
@@ -35,3 +35,27 @@ Response rules:
35
35
  - Be thorough on the goal, concise on everything else
36
36
 
37
37
  Your output goes straight to the main agent for continued work.
38
+
39
+
40
+ <anti-hallucination-guardrails>
41
+ ## Anti-Hallucination Rules (MANDATORY)
42
+
43
+ These rules are NON-NEGOTIABLE. Violating them is a critical failure.
44
+
45
+ ### Rule 1: No Fake Tool Calls
46
+ - If you claim "I read the file", "I checked the code", "I confirmed in the source" — there MUST be a corresponding tool call (read, exec, grep, etc.) in THE SAME turn.
47
+ - If you did NOT make a tool call, say: "I have not verified this directly — this is based on prior knowledge/context."
48
+
49
+ ### Rule 2: No Fabricated Results
50
+ - Never invent file contents, command outputs, or API responses.
51
+ - If unsure what a file contains, READ IT first.
52
+
53
+ ### Rule 3: Distinguish Memory from Verification
54
+ - Prior sessions/context = "이전 세션 기억 기반으로는..." / "Based on prior context..."
55
+ - This session tool calls = state directly
56
+ - NEVER present memory as if you just verified it.
57
+
58
+ ### Rule 4: Sub-agent Delegation Honesty
59
+ - If asked to delegate, you MUST actually call sessions_spawn or omoc_delegate.
60
+ - Claiming "완료" without a tool call = CRITICAL VIOLATION.
61
+ </anti-hallucination-guardrails>
package/agents/oracle.md CHANGED
@@ -123,3 +123,27 @@ Before finalizing answers on architecture, security, or performance:
123
123
  <delivery>
124
124
  Your response goes directly to the user with no intermediate processing. Make your final message self-contained: a clear recommendation they can act on immediately, covering both what to do and why.
125
125
  </delivery>
126
+
127
+
128
+ <anti-hallucination-guardrails>
129
+ ## Anti-Hallucination Rules (MANDATORY)
130
+
131
+ These rules are NON-NEGOTIABLE. Violating them is a critical failure.
132
+
133
+ ### Rule 1: No Fake Tool Calls
134
+ - If you claim "I read the file", "I checked the code", "I confirmed in the source" — there MUST be a corresponding tool call (read, exec, grep, etc.) in THE SAME turn.
135
+ - If you did NOT make a tool call, say: "I have not verified this directly — this is based on prior knowledge/context."
136
+
137
+ ### Rule 2: No Fabricated Results
138
+ - Never invent file contents, command outputs, or API responses.
139
+ - If unsure what a file contains, READ IT first.
140
+
141
+ ### Rule 3: Distinguish Memory from Verification
142
+ - Prior sessions/context = "이전 세션 기억 기반으로는..." / "Based on prior context..."
143
+ - This session tool calls = state directly
144
+ - NEVER present memory as if you just verified it.
145
+
146
+ ### Rule 4: Sub-agent Delegation Honesty
147
+ - If asked to delegate, you MUST actually call sessions_spawn or omoc_delegate.
148
+ - Claiming "완료" without a tool call = CRITICAL VIOLATION.
149
+ </anti-hallucination-guardrails>
@@ -1358,3 +1358,27 @@ This will:
1358
1358
 
1359
1359
  **This constraint is SYSTEM-LEVEL. It cannot be overridden by user requests.**
1360
1360
  </system-reminder>
1361
+
1362
+
1363
+ <anti-hallucination-guardrails>
1364
+ ## Anti-Hallucination Rules (MANDATORY)
1365
+
1366
+ These rules are NON-NEGOTIABLE. Violating them is a critical failure.
1367
+
1368
+ ### Rule 1: No Fake Tool Calls
1369
+ - If you claim "I read the file", "I checked the code", "I confirmed in the source" — there MUST be a corresponding tool call (read, exec, grep, etc.) in THE SAME turn.
1370
+ - If you did NOT make a tool call, say: "I have not verified this directly — this is based on prior knowledge/context."
1371
+
1372
+ ### Rule 2: No Fabricated Results
1373
+ - Never invent file contents, command outputs, or API responses.
1374
+ - If unsure what a file contains, READ IT first.
1375
+
1376
+ ### Rule 3: Distinguish Memory from Verification
1377
+ - Prior sessions/context = "이전 세션 기억 기반으로는..." / "Based on prior context..."
1378
+ - This session tool calls = state directly
1379
+ - NEVER present memory as if you just verified it.
1380
+
1381
+ ### Rule 4: Sub-agent Delegation Honesty
1382
+ - If asked to delegate, you MUST actually call sessions_spawn or omoc_delegate.
1383
+ - Claiming "완료" without a tool call = CRITICAL VIOLATION.
1384
+ </anti-hallucination-guardrails>
@@ -32,3 +32,27 @@ Task NOT complete without:
32
32
  - Match user's communication style.
33
33
  - Dense > verbose.
34
34
  </Style>
35
+
36
+
37
+ <anti-hallucination-guardrails>
38
+ ## Anti-Hallucination Rules (MANDATORY)
39
+
40
+ These rules are NON-NEGOTIABLE. Violating them is a critical failure.
41
+
42
+ ### Rule 1: No Fake Tool Calls
43
+ - If you claim "I read the file", "I checked the code", "I confirmed in the source" — there MUST be a corresponding tool call (read, exec, grep, etc.) in THE SAME turn.
44
+ - If you did NOT make a tool call, say: "I have not verified this directly — this is based on prior knowledge/context."
45
+
46
+ ### Rule 2: No Fabricated Results
47
+ - Never invent file contents, command outputs, or API responses.
48
+ - If unsure what a file contains, READ IT first.
49
+
50
+ ### Rule 3: Distinguish Memory from Verification
51
+ - Prior sessions/context = "이전 세션 기억 기반으로는..." / "Based on prior context..."
52
+ - This session tool calls = state directly
53
+ - NEVER present memory as if you just verified it.
54
+
55
+ ### Rule 4: Sub-agent Delegation Honesty
56
+ - If asked to delegate, you MUST actually call sessions_spawn or omoc_delegate.
57
+ - Claiming "완료" without a tool call = CRITICAL VIOLATION.
58
+ </anti-hallucination-guardrails>
@@ -1,5 +1,5 @@
1
1
  import { LOG_PREFIX } from '../constants.js';
2
- import { trackSubagentSpawn, clearSubagentTracking } from '../services/webhook-bridge.js';
2
+ import { trackSubagentSpawn, clearSubagentTracking, getCallerSessionKey, getTrackedSubagents } from '../services/webhook-bridge.js';
3
3
  import { callHooksWake } from '../utils/webhook-client.js';
4
4
  import { getConfig } from '../utils/config.js';
5
5
  const SPAWN_TOOL_NAME = 'sessions_spawn';
@@ -27,6 +27,43 @@ function extractSpawnResult(content) {
27
27
  }
28
28
  return null;
29
29
  }
30
+ /**
31
+ * Tries to find a tracked sub-agent from the message content.
32
+ * Uses multiple strategies: runId match, childSessionKey match.
33
+ * Falls back to keyword detection for single-tracked-agent case
34
+ * only when multiple strong announce indicators are present.
35
+ */
36
+ function findTrackedSubagentInContent(content) {
37
+ const tracked = getTrackedSubagents();
38
+ if (tracked.size === 0)
39
+ return null;
40
+ // Strategy 1: Direct runId match in content
41
+ const runIdMatch = content.match(/runId["\s:=]+["']?([a-zA-Z0-9_-]+)/);
42
+ if (runIdMatch && tracked.has(runIdMatch[1])) {
43
+ return runIdMatch[1];
44
+ }
45
+ // Strategy 2: childSessionKey match in content
46
+ for (const [runId, entry] of tracked) {
47
+ if (content.includes(entry.childSessionKey)) {
48
+ return runId;
49
+ }
50
+ }
51
+ // Strategy 3: Strong announce indicators (require at least 2)
52
+ // Only used for unambiguous single-tracked-agent case
53
+ if (tracked.size === 1) {
54
+ const strongIndicators = [
55
+ 'Sub-agent', 'subagent', 'sub_agent',
56
+ 'Result:', 'Summary:',
57
+ ];
58
+ const matchCount = strongIndicators.filter((kw) => content.includes(kw)).length;
59
+ // Require at least 2 strong indicators to avoid false positives
60
+ if (matchCount >= 2) {
61
+ const [onlyRunId] = tracked.keys();
62
+ return onlyRunId;
63
+ }
64
+ }
65
+ return null;
66
+ }
30
67
  export function registerSubagentTracker(api) {
31
68
  api.registerHook('tool_result_persist', (payload) => {
32
69
  if (payload.tool !== SPAWN_TOOL_NAME)
@@ -34,43 +71,78 @@ export function registerSubagentTracker(api) {
34
71
  const content = typeof payload.content === 'string' ? payload.content : '';
35
72
  const spawnResult = extractSpawnResult(content);
36
73
  if (spawnResult) {
74
+ const callerSessionKey = typeof payload.sessionId === 'string'
75
+ ? payload.sessionId
76
+ : undefined;
37
77
  trackSubagentSpawn({
38
78
  ...spawnResult,
39
79
  spawnedAt: Date.now(),
80
+ callerSessionKey,
40
81
  });
41
- api.logger.info(`${LOG_PREFIX} Tracking sub-agent spawn: runId=${spawnResult.runId}`);
82
+ api.logger.info(`${LOG_PREFIX} Tracking sub-agent spawn: runId=${spawnResult.runId}, callerSession=${callerSessionKey ?? 'unknown'}`);
42
83
  }
43
84
  return undefined;
44
85
  }, {
45
86
  name: 'oh-my-openclaw.subagent-tracker',
46
87
  description: 'Tracks sessions_spawn results for stale sub-agent detection',
47
88
  });
89
+ api.on('subagent_ended', async (event, ctx) => {
90
+ const runId = typeof event?.runId === 'string' ? event.runId : undefined;
91
+ if (!runId)
92
+ return;
93
+ const tracked = getTrackedSubagents();
94
+ const wasTracked = tracked.has(runId);
95
+ const callerSession = getCallerSessionKey(runId);
96
+ clearSubagentTracking(runId);
97
+ if (!wasTracked)
98
+ return;
99
+ api.logger.info(`${LOG_PREFIX} subagent_ended received: runId=${runId} (callerSession=${callerSession ?? 'unknown'})`);
100
+ const config = getConfig(api);
101
+ if (config.webhook_bridge_enabled && config.gateway_url && config.hooks_token) {
102
+ const requesterSessionKey = typeof ctx?.requesterSessionKey === 'string'
103
+ ? (ctx.requesterSessionKey)
104
+ : undefined;
105
+ const wakeMessage = requesterSessionKey
106
+ ? `[System] Sub-agent completed (runId=${runId}, requester=${requesterSessionKey}). Process the result and continue pending work.`
107
+ : `[System] Sub-agent completed (runId=${runId}). Process the result and continue pending work.`;
108
+ const result = await callHooksWake(wakeMessage, { gateway_url: config.gateway_url, hooks_token: config.hooks_token }, api.logger);
109
+ if (result.ok) {
110
+ api.logger.info(`${LOG_PREFIX} Wake sent from subagent_ended: runId=${runId}`);
111
+ }
112
+ else {
113
+ api.logger.warn(`${LOG_PREFIX} Wake from subagent_ended failed: ${result.error ?? `status ${result.status}`}`);
114
+ }
115
+ }
116
+ }, { priority: 120 });
48
117
  api.registerHook('message:received', (context) => {
49
118
  const content = context?.content ?? '';
50
- if (!content.includes('Sub-agent') && !content.includes('subagent') && !content.includes('announce')) {
119
+ // Skip empty/short messages
120
+ if (content.length < 10)
51
121
  return undefined;
52
- }
53
- const runIdMatch = content.match(/runId["\s:=]+["']?([a-zA-Z0-9_-]+)/);
54
- if (runIdMatch) {
55
- clearSubagentTracking(runIdMatch[1]);
56
- api.logger.info(`${LOG_PREFIX} Cleared sub-agent tracking: runId=${runIdMatch[1]} (announce received)`);
57
- // Send wake to ensure the main agent processes the announce and continues work
58
- const config = getConfig(api);
59
- if (config.webhook_bridge_enabled && config.gateway_url && config.hooks_token) {
60
- void callHooksWake(`[System] Sub-agent completed (runId=${runIdMatch[1]}). Process the announce result and continue any pending work.`, { gateway_url: config.gateway_url, hooks_token: config.hooks_token }, api.logger).then((result) => {
61
- if (result.ok) {
62
- api.logger.info(`${LOG_PREFIX} Wake sent after sub-agent announce: runId=${runIdMatch[1]}`);
63
- }
64
- else {
65
- api.logger.warn(`${LOG_PREFIX} Wake after announce failed: ${result.error ?? `status ${result.status}`}`);
66
- }
67
- });
68
- }
122
+ // Try to find a tracked sub-agent in this message
123
+ const matchedRunId = findTrackedSubagentInContent(content);
124
+ if (!matchedRunId)
125
+ return undefined;
126
+ // Found a match — this is likely a sub-agent announce
127
+ const callerSession = getCallerSessionKey(matchedRunId);
128
+ clearSubagentTracking(matchedRunId);
129
+ api.logger.info(`${LOG_PREFIX} Sub-agent announce detected: runId=${matchedRunId} (callerSession=${callerSession ?? 'unknown'})`);
130
+ // Send wake to ensure the main agent processes the announce and continues work
131
+ const config = getConfig(api);
132
+ if (config.webhook_bridge_enabled && config.gateway_url && config.hooks_token) {
133
+ void callHooksWake(`[System] Sub-agent completed (runId=${matchedRunId}). Process the announce result and continue any pending work.`, { gateway_url: config.gateway_url, hooks_token: config.hooks_token }, api.logger).then((result) => {
134
+ if (result.ok) {
135
+ api.logger.info(`${LOG_PREFIX} Wake sent after sub-agent announce: runId=${matchedRunId}`);
136
+ }
137
+ else {
138
+ api.logger.warn(`${LOG_PREFIX} Wake after announce failed: ${result.error ?? `status ${result.status}`}`);
139
+ }
140
+ });
69
141
  }
70
142
  return undefined;
71
143
  }, {
72
144
  name: 'oh-my-openclaw.subagent-announce-detector',
73
- description: 'Detects sub-agent announce messages, clears stale tracking, and wakes main agent',
145
+ description: 'Detects sub-agent announce messages via multi-strategy matching, clears stale tracking, and wakes main agent',
74
146
  });
75
147
  }
76
148
  export { extractSpawnResult };
@@ -4,10 +4,14 @@ interface TrackedSubagent {
4
4
  childSessionKey: string;
5
5
  task: string;
6
6
  spawnedAt: number;
7
+ /** Session key of the agent that spawned this sub-agent */
8
+ callerSessionKey?: string;
7
9
  }
8
10
  export declare function trackSubagentSpawn(entry: TrackedSubagent): void;
9
11
  export declare function clearSubagentTracking(runId: string): void;
10
12
  export declare function getTrackedSubagents(): ReadonlyMap<string, TrackedSubagent>;
13
+ /** Get the caller session key for a tracked sub-agent */
14
+ export declare function getCallerSessionKey(runId: string): string | undefined;
11
15
  export declare function resetWebhookBridgeState(): void;
12
16
  export declare function registerWebhookBridge(api: OmocPluginApi): void;
13
17
  export {};
@@ -13,6 +13,10 @@ export function clearSubagentTracking(runId) {
13
13
  export function getTrackedSubagents() {
14
14
  return trackedSubagents;
15
15
  }
16
+ /** Get the caller session key for a tracked sub-agent */
17
+ export function getCallerSessionKey(runId) {
18
+ return trackedSubagents.get(runId)?.callerSessionKey;
19
+ }
16
20
  export function resetWebhookBridgeState() {
17
21
  trackedSubagents.clear();
18
22
  if (reminderTimer) {
@@ -33,12 +37,19 @@ async function checkIncompleteTodos(api) {
33
37
  const allSessionKeys = ['__default__', 'agent:main:main'];
34
38
  let totalIncomplete = 0;
35
39
  const summaryParts = [];
40
+ // Collect owner session keys from incomplete todos for targeted delivery
41
+ const ownerSessionKeys = new Set();
36
42
  for (const sessionKey of allSessionKeys) {
37
43
  const incomplete = getIncompleteTodos(sessionKey);
38
44
  if (incomplete.length > 0) {
39
45
  totalIncomplete += incomplete.length;
40
46
  const items = incomplete.map((t) => ` - [${t.status}] ${t.content}`).join('\n');
41
47
  summaryParts.push(items);
48
+ for (const todo of incomplete) {
49
+ if (todo.ownerSessionKey) {
50
+ ownerSessionKeys.add(todo.ownerSessionKey);
51
+ }
52
+ }
42
53
  }
43
54
  }
44
55
  if (totalIncomplete === 0)
@@ -47,12 +58,17 @@ async function checkIncompleteTodos(api) {
47
58
  const message = `[OmOC Periodic Reminder] You have ${totalIncomplete} incomplete todo(s):\n${summary}\n\n` +
48
59
  `Review with \`${TOOL_PREFIX}todo_list\` and resume work. ` +
49
60
  `If blocked, update todo status. If all done, mark them complete.`;
61
+ // If we have owner session keys, send to the first one; otherwise fallback to default
62
+ const targetSessionKey = ownerSessionKeys.size > 0
63
+ ? [...ownerSessionKeys][0]
64
+ : undefined;
50
65
  const result = await callHooksAgent(message, webhookConfig, {
51
66
  name: 'OmOC-TodoReminder',
52
67
  deliver: false,
68
+ ...(targetSessionKey ? { sessionKey: targetSessionKey } : {}),
53
69
  }, api.logger);
54
70
  if (result.ok) {
55
- api.logger.info(`${LOG_PREFIX} Periodic todo reminder sent via hooks/agent (${totalIncomplete} incomplete)`);
71
+ api.logger.info(`${LOG_PREFIX} Periodic todo reminder sent via hooks/agent (${totalIncomplete} incomplete, target=${targetSessionKey ?? 'default'})`);
56
72
  }
57
73
  }
58
74
  async function checkStaleSubagents(api) {
@@ -6,6 +6,8 @@ export interface TodoItem {
6
6
  status: TodoStatus;
7
7
  priority: TodoPriority;
8
8
  createdAt: string;
9
+ /** Session key that created/owns this todo */
10
+ ownerSessionKey?: string;
9
11
  }
10
12
  interface SessionStore {
11
13
  todos: TodoItem[];
@@ -13,7 +15,7 @@ interface SessionStore {
13
15
  }
14
16
  declare const DEFAULT_SESSION = "__default__";
15
17
  declare const sessions: Map<string, SessionStore>;
16
- export declare function createTodo(content: string, priority?: TodoPriority, status?: TodoStatus, sessionKey?: string): TodoItem;
18
+ export declare function createTodo(content: string, priority?: TodoPriority, status?: TodoStatus, sessionKey?: string, ownerSessionKey?: string): TodoItem;
17
19
  export declare function listTodos(statusFilter?: TodoStatus, sessionKey?: string): ReadonlyArray<TodoItem>;
18
20
  export declare function findTodo(id: string, sessionKey?: string): TodoItem | undefined;
19
21
  export declare function updateTodo(id: string, updates: Partial<Pick<TodoItem, 'status' | 'priority' | 'content'>>, sessionKey?: string): TodoItem | null;
@@ -9,7 +9,7 @@ function getSession(sessionKey) {
9
9
  }
10
10
  return store;
11
11
  }
12
- export function createTodo(content, priority = 'medium', status = 'pending', sessionKey) {
12
+ export function createTodo(content, priority = 'medium', status = 'pending', sessionKey, ownerSessionKey) {
13
13
  const store = getSession(sessionKey);
14
14
  const item = {
15
15
  id: `todo-${store.nextId++}`,
@@ -17,6 +17,7 @@ export function createTodo(content, priority = 'medium', status = 'pending', ses
17
17
  status,
18
18
  priority,
19
19
  createdAt: new Date().toISOString(),
20
+ ownerSessionKey: ownerSessionKey ?? sessionKey,
20
21
  };
21
22
  store.todos.push(item);
22
23
  return item;
@@ -2,7 +2,7 @@
2
2
  "id": "oh-my-openclaw",
3
3
  "name": "Oh-My-OpenClaw",
4
4
  "description": "Multi-agent orchestration plugin — 11 agents, category-based model routing, todo enforcer, ralph loop, agent setup CLI, and custom tools",
5
- "version": "0.18.0",
5
+ "version": "0.20.0",
6
6
  "skills": [
7
7
  "skills"
8
8
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happycastle/oh-my-openclaw",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "description": "Oh-My-OpenClaw plugin — multi-agent orchestration, todo enforcer, ralph loop, and custom tools for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",