oh-my-customcode 0.78.0 → 0.78.1
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/README.md +2 -2
- package/dist/cli/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/.claude/hooks/hooks.json +1 -1
- package/templates/.claude/hooks/scripts/auto-continue-guard.sh +33 -0
- package/templates/CLAUDE.md +1 -1
- package/templates/guides/hook-data-flow/README.md +135 -0
- package/templates/manifest.json +2 -2
package/README.md
CHANGED
|
@@ -235,7 +235,7 @@ Key rules: R010 (orchestrator never writes files), R009 (parallel execution mand
|
|
|
235
235
|
|
|
236
236
|
---
|
|
237
237
|
|
|
238
|
-
### Guides (
|
|
238
|
+
### Guides (32)
|
|
239
239
|
|
|
240
240
|
Reference documentation covering best practices, architecture decisions, and integration patterns. Located in `guides/` at project root, covering topics from agent design to CI/CD to observability.
|
|
241
241
|
|
|
@@ -292,7 +292,7 @@ your-project/
|
|
|
292
292
|
│ ├── specs/ # Extracted canonical specs
|
|
293
293
|
│ ├── contexts/ # 4 shared context files
|
|
294
294
|
│ └── ontology/ # Knowledge graph for RAG
|
|
295
|
-
└── guides/ #
|
|
295
|
+
└── guides/ # 32 reference documents
|
|
296
296
|
```
|
|
297
297
|
|
|
298
298
|
---
|
package/dist/cli/index.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -189,7 +189,7 @@
|
|
|
189
189
|
},
|
|
190
190
|
{
|
|
191
191
|
"type": "command",
|
|
192
|
-
"command": "
|
|
192
|
+
"command": "bash .claude/hooks/scripts/auto-continue-guard.sh"
|
|
193
193
|
},
|
|
194
194
|
{
|
|
195
195
|
"type": "prompt",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Auto-Continue Guard
|
|
5
|
+
# Trigger: SubagentStop
|
|
6
|
+
# Purpose: Count consecutive subagent completions and warn when auto-continue limit reached
|
|
7
|
+
# Protocol: stdin JSON -> count check -> stdout pass-through, exit 0 always (R021)
|
|
8
|
+
|
|
9
|
+
input=$(cat)
|
|
10
|
+
|
|
11
|
+
count_file="/tmp/.claude-loop-count-${PPID}"
|
|
12
|
+
|
|
13
|
+
# Reset counter if stale (>60s since last update)
|
|
14
|
+
if [ -f "$count_file" ]; then
|
|
15
|
+
last_mod=$(stat -c%Y "$count_file" 2>/dev/null || stat -f%m "$count_file" 2>/dev/null || echo 0)
|
|
16
|
+
now=$(date +%s)
|
|
17
|
+
if [ $((now - last_mod)) -gt 60 ]; then
|
|
18
|
+
echo 0 > "$count_file"
|
|
19
|
+
fi
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# Increment counter
|
|
23
|
+
count=$(cat "$count_file" 2>/dev/null || echo 0)
|
|
24
|
+
count=$((count + 1))
|
|
25
|
+
echo "$count" > "$count_file"
|
|
26
|
+
|
|
27
|
+
# Warn if limit reached
|
|
28
|
+
if [ "$count" -ge 4 ]; then
|
|
29
|
+
echo '[AutoContinue] SAFETY: auto-continue limit (3) reached. Pausing.' >&2
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
echo "$input"
|
|
33
|
+
exit 0
|
package/templates/CLAUDE.md
CHANGED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Hook Data Flow: Stall Detection Pipeline
|
|
2
|
+
|
|
3
|
+
Added in v0.78.0. Documents the three-script pipeline that detects stalled parallel agents and emits R009 Adaptive Parallel Splitting advisories.
|
|
4
|
+
|
|
5
|
+
Related rule: `.claude/rules/MUST-parallel-execution.md` (R009 Adaptive Parallel Splitting section)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
When multiple agents run in parallel, one agent may take significantly longer than its peers. The stall detection pipeline identifies this condition at the moment any agent completes and advises the orchestrator to spawn independent pending tasks immediately — without cancelling the stalled agent.
|
|
12
|
+
|
|
13
|
+
The pipeline spans two hook events and three scripts:
|
|
14
|
+
|
|
15
|
+
| Event | Script | Role |
|
|
16
|
+
|-------|--------|------|
|
|
17
|
+
| SubagentStart | `agent-start-recorder.sh` | Record spawn timestamp |
|
|
18
|
+
| SubagentStop (1st) | `task-outcome-recorder.sh` | Read start time, record outcome with duration |
|
|
19
|
+
| SubagentStop (2nd) | `stall-detection-advisor.sh` | Read start times, compare durations, emit advisory, consume start entry |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Data Flow
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
SubagentStart event
|
|
27
|
+
└─ agent-start-recorder.sh
|
|
28
|
+
reads: stdin JSON (agent_type, model, description)
|
|
29
|
+
writes: /tmp/.claude-agent-starts-$PPID (appends 1 JSON line)
|
|
30
|
+
|
|
31
|
+
SubagentStop event [hooks execute in array order — ordering is critical]
|
|
32
|
+
│
|
|
33
|
+
├─ [1] task-outcome-recorder.sh
|
|
34
|
+
│ reads: stdin JSON (agent_type, model, outcome)
|
|
35
|
+
│ reads: /tmp/.claude-agent-starts-$PPID (duration calc — entry still present)
|
|
36
|
+
│ writes: /tmp/.claude-task-outcomes-$PPID (appends 1 JSON line with duration_seconds)
|
|
37
|
+
│ writes: stderr (on failure only)
|
|
38
|
+
│
|
|
39
|
+
└─ [2] stall-detection-advisor.sh
|
|
40
|
+
reads: stdin JSON (agent_type, model, description)
|
|
41
|
+
reads: /tmp/.claude-agent-starts-$PPID (finds matching start entry for duration)
|
|
42
|
+
reads: /tmp/.claude-agent-durations-$PPID (peer durations for average calculation)
|
|
43
|
+
writes: /tmp/.claude-agent-durations-$PPID (appends completed agent's duration)
|
|
44
|
+
writes: /tmp/.claude-agent-starts-$PPID (removes consumed start entry)
|
|
45
|
+
writes: stderr (advisory block if stall detected — R021 advisory-only)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Stall Detection Logic
|
|
49
|
+
|
|
50
|
+
At SubagentStop, after at least one peer has already completed:
|
|
51
|
+
|
|
52
|
+
1. Calculate `avg_duration` from all entries in `.claude-agent-durations-$PPID`
|
|
53
|
+
2. Set `stall_threshold = avg_duration * 2`
|
|
54
|
+
3. Scan `.claude-agent-starts-$PPID` for agents not yet in the duration file (still running)
|
|
55
|
+
4. For each still-running agent where `elapsed > stall_threshold`, emit advisory to stderr
|
|
56
|
+
|
|
57
|
+
The current agent's duration is recorded *after* stall detection so it does not inflate the average for its own check.
|
|
58
|
+
|
|
59
|
+
### Advisory Output Format
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
─── [Stall Detection Advisory] ───────────────────────────
|
|
63
|
+
Stalled: {agent_type}:{model} ({elapsed}s elapsed, 2x avg {avg_duration}s)
|
|
64
|
+
Description: {description}
|
|
65
|
+
⚡ Consider spawning independent pending tasks immediately
|
|
66
|
+
R009 Adaptive Parallel Splitting applies
|
|
67
|
+
──────────────────────────────────────────────────────────
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Shared Files
|
|
73
|
+
|
|
74
|
+
| File | Writer | Readers | Lifecycle |
|
|
75
|
+
|------|--------|---------|-----------|
|
|
76
|
+
| `/tmp/.claude-agent-starts-$PPID` | `agent-start-recorder.sh` (append) | `task-outcome-recorder.sh` (read), `stall-detection-advisor.sh` (read + remove entry) | Session-scoped via PPID; ring buffer 50 entries; entry removed after `stall-detection-advisor` consumes it |
|
|
77
|
+
| `/tmp/.claude-task-outcomes-$PPID` | `task-outcome-recorder.sh` (append) | `feedback-collector.sh`, `eval-core-batch-save.sh` (at Stop) | Session-scoped via PPID; ring buffer 50 entries |
|
|
78
|
+
| `/tmp/.claude-agent-durations-$PPID` | `stall-detection-advisor.sh` (append) | `stall-detection-advisor.sh` (read for average calculation) | Session-scoped via PPID; ring buffer 50 entries |
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Execution Order Requirements
|
|
83
|
+
|
|
84
|
+
The SubagentStop hook array in `hooks.json` defines a strict ordering:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
"SubagentStop": [
|
|
88
|
+
{ "command": "bash .claude/hooks/scripts/task-outcome-recorder.sh" },
|
|
89
|
+
{ "command": "bash .claude/hooks/scripts/stall-detection-advisor.sh" },
|
|
90
|
+
...
|
|
91
|
+
]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**task-outcome-recorder MUST run before stall-detection-advisor.**
|
|
95
|
+
|
|
96
|
+
Reason: `stall-detection-advisor.sh` removes the matching start entry from `.claude-agent-starts-$PPID` after reading it (to prevent re-matching on the next SubagentStop). If the order were reversed, `task-outcome-recorder.sh` would find no start entry for the agent and would always record `duration_seconds=0`.
|
|
97
|
+
|
|
98
|
+
If the order is swapped:
|
|
99
|
+
- `task-outcome-recorder` records `duration_seconds=0` for all agents
|
|
100
|
+
- Model escalation decisions based on duration become unreliable
|
|
101
|
+
- No other visible error — silent data corruption
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Temp File Lifecycle
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
Session start (PPID assigned)
|
|
109
|
+
│
|
|
110
|
+
├─ First SubagentStart → .claude-agent-starts-$PPID created
|
|
111
|
+
│
|
|
112
|
+
├─ First SubagentStop → .claude-task-outcomes-$PPID created
|
|
113
|
+
│ .claude-agent-durations-$PPID created
|
|
114
|
+
│
|
|
115
|
+
├─ Each SubagentStop → start entry consumed (removed by stall-detection-advisor)
|
|
116
|
+
│ duration entry appended
|
|
117
|
+
│ outcome entry appended
|
|
118
|
+
│
|
|
119
|
+
└─ Session end (PPID released)
|
|
120
|
+
Files remain in /tmp — OS cleans up on reboot
|
|
121
|
+
Ring buffers cap each file at 50 lines to bound growth
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
PPID (parent process ID) is used rather than PID (`$$`) to scope files to the Claude Code session rather than to individual script invocations. All three scripts use `${PPID}` consistently.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Design Principles
|
|
129
|
+
|
|
130
|
+
- **Advisory-only (R021):** All three scripts exit 0 unconditionally. A missing `jq` binary causes silent pass-through, not a blocked hook.
|
|
131
|
+
- **PPID scoping:** Isolates temp files per Claude Code session. Multiple concurrent sessions do not interfere.
|
|
132
|
+
- **Ring buffers:** Each temp file is capped at 50 lines via `tail -50` after each append. Prevents unbounded growth in long sessions with many agents.
|
|
133
|
+
- **grep -F for pattern matching:** Fixed-string matching in `agent-start-recorder` and `task-outcome-recorder` avoids regex injection from agent type names.
|
|
134
|
+
- **Self-exclusion from average:** `stall-detection-advisor` reads the duration file *before* appending its own entry, so the completing agent is never compared against itself.
|
|
135
|
+
- **Sibling preservation:** When removing a start entry, `awk` removes only the first matching line — preserving sibling entries when multiple agents of the same type run in parallel.
|
package/templates/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.78.
|
|
2
|
+
"version": "0.78.1",
|
|
3
3
|
"lastUpdated": "2026-03-24T00:00:00.000Z",
|
|
4
4
|
"components": [
|
|
5
5
|
{
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"name": "guides",
|
|
25
25
|
"path": "guides",
|
|
26
26
|
"description": "Reference documentation",
|
|
27
|
-
"files":
|
|
27
|
+
"files": 32
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"name": "hooks",
|