continuous-improvement 1.0.0 → 2.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.
- package/CHANGELOG.md +87 -0
- package/QUICKSTART.md +81 -0
- package/README.md +107 -121
- package/SKILL.md +171 -0
- package/bin/analyze.sh +115 -0
- package/bin/install.mjs +266 -0
- package/commands/continuous-improvement.md +74 -0
- package/hooks/observe.sh +63 -62
- package/package.json +31 -14
- package/agents/observer-loop.sh +0 -282
- package/agents/observer.md +0 -145
- package/agents/start-observer.sh +0 -115
- package/config.json +0 -9
- package/docs/failure-taxonomy.md +0 -153
- package/docs/integration-guide.md +0 -105
- package/docs/philosophy.md +0 -127
- package/docs/superpowers/plans/2026-04-05-mulahazah-implementation.md +0 -1666
- package/docs/superpowers/specs/2026-04-05-mulahazah-instinct-learning-design.md +0 -636
- package/prompts/coding-agent.md +0 -67
- package/prompts/core.md +0 -115
- package/prompts/minimal.md +0 -17
- package/prompts/product-agent.md +0 -59
- package/prompts/research-agent.md +0 -59
- package/scripts/install.js +0 -433
- package/skills/continuous-improvement/SKILL.md +0 -111
package/package.json
CHANGED
|
@@ -1,23 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "continuous-improvement",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "7-law discipline framework with auto-leveling instinct learning for AI agents — research, plan, execute, verify, reflect, learn, iterate",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai-agent",
|
|
7
|
+
"claude-code",
|
|
8
|
+
"codex",
|
|
9
|
+
"openclaw",
|
|
10
|
+
"cursor",
|
|
11
|
+
"skill",
|
|
12
|
+
"continuous-improvement",
|
|
13
|
+
"workflow",
|
|
14
|
+
"productivity",
|
|
15
|
+
"mulahazah",
|
|
16
|
+
"instinct",
|
|
17
|
+
"learning",
|
|
18
|
+
"hooks"
|
|
19
|
+
],
|
|
20
|
+
"author": "naimkatiman",
|
|
5
21
|
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/naimkatiman/continuous-improvement"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/naimkatiman/continuous-improvement#readme",
|
|
6
27
|
"bin": {
|
|
7
|
-
"continuous-improvement": "
|
|
28
|
+
"continuous-improvement": "./bin/install.mjs"
|
|
8
29
|
},
|
|
9
30
|
"files": [
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"hooks/",
|
|
14
|
-
"agents/",
|
|
15
|
-
"config.json",
|
|
31
|
+
"SKILL.md",
|
|
32
|
+
"QUICKSTART.md",
|
|
33
|
+
"CHANGELOG.md",
|
|
16
34
|
"README.md",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
35
|
+
"bin/",
|
|
36
|
+
"hooks/",
|
|
37
|
+
"commands/"
|
|
19
38
|
],
|
|
20
|
-
"
|
|
21
|
-
"node": ">=18"
|
|
22
|
-
}
|
|
39
|
+
"type": "module"
|
|
23
40
|
}
|
package/agents/observer-loop.sh
DELETED
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# observer-loop.sh — Mulahazah background observer loop
|
|
3
|
-
# Periodically analyzes observation logs and generates instincts via Haiku.
|
|
4
|
-
# Started by start-observer.sh. Should not be invoked directly.
|
|
5
|
-
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
MULAHAZAH_DIR="${HOME}/.claude/mulahazah"
|
|
9
|
-
CONFIG_FILE="${MULAHAZAH_DIR}/config.json"
|
|
10
|
-
PROJECTS_DIR="${MULAHAZAH_DIR}/projects"
|
|
11
|
-
INSTINCTS_DIR="${MULAHAZAH_DIR}/instincts"
|
|
12
|
-
OBSERVER_PROMPT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/observer.md"
|
|
13
|
-
LOG_FILE="${MULAHAZAH_DIR}/observer.log"
|
|
14
|
-
|
|
15
|
-
# ---------------------------------------------------------------------------
|
|
16
|
-
# Logging
|
|
17
|
-
# ---------------------------------------------------------------------------
|
|
18
|
-
log() {
|
|
19
|
-
local level="$1"; shift
|
|
20
|
-
printf '[%s] [%s] %s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$level" "$*" >> "$LOG_FILE"
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
# ---------------------------------------------------------------------------
|
|
24
|
-
# Read config values (with defaults)
|
|
25
|
-
# ---------------------------------------------------------------------------
|
|
26
|
-
read_config() {
|
|
27
|
-
local key="$1"
|
|
28
|
-
local default="$2"
|
|
29
|
-
if [[ -f "$CONFIG_FILE" ]]; then
|
|
30
|
-
local val
|
|
31
|
-
val="$(jq -r "${key} // empty" "$CONFIG_FILE" 2>/dev/null || true)"
|
|
32
|
-
if [[ -n "$val" && "$val" != "null" ]]; then
|
|
33
|
-
printf '%s' "$val"
|
|
34
|
-
return
|
|
35
|
-
fi
|
|
36
|
-
fi
|
|
37
|
-
printf '%s' "$default"
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
# ---------------------------------------------------------------------------
|
|
41
|
-
# Signal handling
|
|
42
|
-
# ---------------------------------------------------------------------------
|
|
43
|
-
FORCE_RUN=false
|
|
44
|
-
SHUTDOWN=false
|
|
45
|
-
|
|
46
|
-
handle_sigterm() {
|
|
47
|
-
log INFO "Received SIGTERM — shutting down gracefully"
|
|
48
|
-
SHUTDOWN=true
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
handle_sigusr1() {
|
|
52
|
-
log INFO "Received SIGUSR1 — forcing immediate analysis run"
|
|
53
|
-
FORCE_RUN=true
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
trap handle_sigterm SIGTERM
|
|
57
|
-
trap handle_sigusr1 SIGUSR1
|
|
58
|
-
|
|
59
|
-
# ---------------------------------------------------------------------------
|
|
60
|
-
# Analyze a single project directory
|
|
61
|
-
# ---------------------------------------------------------------------------
|
|
62
|
-
analyze_project() {
|
|
63
|
-
local project_dir="$1"
|
|
64
|
-
local obs_file="${project_dir}/observations.jsonl"
|
|
65
|
-
local project_json="${project_dir}/project.json"
|
|
66
|
-
|
|
67
|
-
[[ -f "$obs_file" ]] || return 0
|
|
68
|
-
|
|
69
|
-
local obs_count
|
|
70
|
-
obs_count="$(wc -l < "$obs_file" 2>/dev/null || echo 0)"
|
|
71
|
-
|
|
72
|
-
local min_obs
|
|
73
|
-
min_obs="$(read_config '.observer.min_observations_to_analyze' '20')"
|
|
74
|
-
|
|
75
|
-
if (( obs_count < min_obs )); then
|
|
76
|
-
log DEBUG "Skipping ${project_dir} — only ${obs_count} observations (min: ${min_obs})"
|
|
77
|
-
return 0
|
|
78
|
-
fi
|
|
79
|
-
|
|
80
|
-
local project_id project_name
|
|
81
|
-
project_id="$(basename "$project_dir")"
|
|
82
|
-
project_name="$(jq -r '.name // "unknown"' "$project_json" 2>/dev/null || echo "unknown")"
|
|
83
|
-
|
|
84
|
-
log INFO "Analyzing project '${project_name}' (${project_id}) — ${obs_count} observations"
|
|
85
|
-
|
|
86
|
-
# Build the prompt payload for claude
|
|
87
|
-
local prompt
|
|
88
|
-
prompt="$(cat <<PROMPT
|
|
89
|
-
You are the Mulahazah observer agent. Analyze the following observation data and existing instincts.
|
|
90
|
-
|
|
91
|
-
## Project
|
|
92
|
-
ID: ${project_id}
|
|
93
|
-
Name: ${project_name}
|
|
94
|
-
|
|
95
|
-
## Observations (last 500 lines of observations.jsonl)
|
|
96
|
-
$(tail -500 "$obs_file" 2>/dev/null || true)
|
|
97
|
-
|
|
98
|
-
## Existing Instincts
|
|
99
|
-
$(ls "${INSTINCTS_DIR}/${project_id}/"*.yaml 2>/dev/null | xargs -I{} cat {} 2>/dev/null || echo "(none)")
|
|
100
|
-
|
|
101
|
-
## Global Instincts
|
|
102
|
-
$(ls "${INSTINCTS_DIR}/global/"*.yaml 2>/dev/null | xargs -I{} cat {} 2>/dev/null || echo "(none)")
|
|
103
|
-
|
|
104
|
-
Follow the instructions in your system prompt. Output only YAML instinct blocks.
|
|
105
|
-
PROMPT
|
|
106
|
-
)"
|
|
107
|
-
|
|
108
|
-
# Run claude with observer.md as the system prompt
|
|
109
|
-
local output
|
|
110
|
-
output="$(printf '%s' "$prompt" | \
|
|
111
|
-
claude --model haiku --print --system-prompt "$OBSERVER_PROMPT" 2>>"$LOG_FILE" || true)"
|
|
112
|
-
|
|
113
|
-
if [[ -z "$output" ]]; then
|
|
114
|
-
log WARN "No output from observer for project '${project_name}'"
|
|
115
|
-
return 0
|
|
116
|
-
fi
|
|
117
|
-
|
|
118
|
-
# Write instincts to disk
|
|
119
|
-
write_instincts "$output" "$project_id"
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
# ---------------------------------------------------------------------------
|
|
123
|
-
# Analyze global observations
|
|
124
|
-
# ---------------------------------------------------------------------------
|
|
125
|
-
analyze_global() {
|
|
126
|
-
local global_dir="${PROJECTS_DIR}/global"
|
|
127
|
-
local obs_file="${global_dir}/observations.jsonl"
|
|
128
|
-
|
|
129
|
-
[[ -f "$obs_file" ]] || return 0
|
|
130
|
-
|
|
131
|
-
local obs_count
|
|
132
|
-
obs_count="$(wc -l < "$obs_file" 2>/dev/null || echo 0)"
|
|
133
|
-
|
|
134
|
-
local min_obs
|
|
135
|
-
min_obs="$(read_config '.observer.min_observations_to_analyze' '20')"
|
|
136
|
-
|
|
137
|
-
if (( obs_count < min_obs )); then
|
|
138
|
-
log DEBUG "Skipping global observations — only ${obs_count} lines (min: ${min_obs})"
|
|
139
|
-
return 0
|
|
140
|
-
fi
|
|
141
|
-
|
|
142
|
-
log INFO "Analyzing global observations — ${obs_count} lines"
|
|
143
|
-
|
|
144
|
-
local prompt
|
|
145
|
-
prompt="$(cat <<PROMPT
|
|
146
|
-
You are the Mulahazah observer agent. Analyze the following global observation data.
|
|
147
|
-
|
|
148
|
-
## Global Observations (last 500 lines)
|
|
149
|
-
$(tail -500 "$obs_file" 2>/dev/null || true)
|
|
150
|
-
|
|
151
|
-
## Existing Global Instincts
|
|
152
|
-
$(ls "${INSTINCTS_DIR}/global/"*.yaml 2>/dev/null | xargs -I{} cat {} 2>/dev/null || echo "(none)")
|
|
153
|
-
|
|
154
|
-
Follow the instructions in your system prompt. Output only YAML instinct blocks with scope: global.
|
|
155
|
-
PROMPT
|
|
156
|
-
)"
|
|
157
|
-
|
|
158
|
-
local output
|
|
159
|
-
output="$(printf '%s' "$prompt" | \
|
|
160
|
-
claude --model haiku --print --system-prompt "$OBSERVER_PROMPT" 2>>"$LOG_FILE" || true)"
|
|
161
|
-
|
|
162
|
-
if [[ -z "$output" ]]; then
|
|
163
|
-
log WARN "No output from observer for global observations"
|
|
164
|
-
return 0
|
|
165
|
-
fi
|
|
166
|
-
|
|
167
|
-
write_instincts "$output" "global"
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
# ---------------------------------------------------------------------------
|
|
171
|
-
# Parse and write instinct YAML blocks to disk
|
|
172
|
-
# ---------------------------------------------------------------------------
|
|
173
|
-
write_instincts() {
|
|
174
|
-
local yaml_output="$1"
|
|
175
|
-
local project_id="$2"
|
|
176
|
-
|
|
177
|
-
# Split on --- separators and process each block
|
|
178
|
-
local instinct_dir="${INSTINCTS_DIR}/${project_id}"
|
|
179
|
-
mkdir -p "$instinct_dir"
|
|
180
|
-
|
|
181
|
-
# Write raw output to a temp file, then split by ---
|
|
182
|
-
local tmpfile
|
|
183
|
-
tmpfile="$(mktemp)"
|
|
184
|
-
printf '%s' "$yaml_output" > "$tmpfile"
|
|
185
|
-
|
|
186
|
-
# Use awk to split YAML documents on '---' separator
|
|
187
|
-
awk 'BEGIN{n=0; block=""} /^---$/{if(block!=""){print block > "/tmp/mulahazah_instinct_"n".yaml"; n++; block=""}} !/^---$/{block=block"\n"$0} END{if(block!=""){print block > "/tmp/mulahazah_instinct_"n".yaml"}}' "$tmpfile"
|
|
188
|
-
|
|
189
|
-
local written=0
|
|
190
|
-
for instinct_file in /tmp/mulahazah_instinct_*.yaml; do
|
|
191
|
-
[[ -f "$instinct_file" ]] || continue
|
|
192
|
-
|
|
193
|
-
# Extract the instinct id
|
|
194
|
-
local instinct_id
|
|
195
|
-
instinct_id="$(grep -m1 '^id:' "$instinct_file" | sed 's/^id: *//' | tr -d '"' | tr -d "'" | xargs 2>/dev/null || true)"
|
|
196
|
-
|
|
197
|
-
if [[ -z "$instinct_id" ]]; then
|
|
198
|
-
log WARN "Skipping instinct block with no id"
|
|
199
|
-
rm -f "$instinct_file"
|
|
200
|
-
continue
|
|
201
|
-
fi
|
|
202
|
-
|
|
203
|
-
local dest="${instinct_dir}/${instinct_id}.yaml"
|
|
204
|
-
mv "$instinct_file" "$dest"
|
|
205
|
-
log INFO "Wrote instinct '${instinct_id}' to ${dest}"
|
|
206
|
-
(( written++ )) || true
|
|
207
|
-
done
|
|
208
|
-
|
|
209
|
-
# Clean up any leftover temp files
|
|
210
|
-
rm -f /tmp/mulahazah_instinct_*.yaml "$tmpfile"
|
|
211
|
-
|
|
212
|
-
log INFO "Wrote ${written} instincts for project '${project_id}'"
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
# ---------------------------------------------------------------------------
|
|
216
|
-
# Main loop
|
|
217
|
-
# ---------------------------------------------------------------------------
|
|
218
|
-
main() {
|
|
219
|
-
log INFO "Mulahazah observer loop started (PID $$)"
|
|
220
|
-
|
|
221
|
-
# Validate dependencies
|
|
222
|
-
command -v jq &>/dev/null || { log ERROR "jq not found — observer cannot run"; exit 1; }
|
|
223
|
-
command -v claude &>/dev/null || { log ERROR "claude CLI not found — observer cannot run"; exit 1; }
|
|
224
|
-
[[ -f "$OBSERVER_PROMPT" ]] || { log ERROR "observer.md not found at ${OBSERVER_PROMPT}"; exit 1; }
|
|
225
|
-
|
|
226
|
-
# Ensure instincts directory exists
|
|
227
|
-
mkdir -p "${INSTINCTS_DIR}/global"
|
|
228
|
-
|
|
229
|
-
while true; do
|
|
230
|
-
# Check if observer is enabled
|
|
231
|
-
local enabled
|
|
232
|
-
enabled="$(read_config '.observer.enabled' 'true')"
|
|
233
|
-
if [[ "$enabled" != "true" ]]; then
|
|
234
|
-
log INFO "Observer is disabled in config — sleeping"
|
|
235
|
-
sleep 60
|
|
236
|
-
[[ "$SHUTDOWN" == "true" ]] && break
|
|
237
|
-
continue
|
|
238
|
-
fi
|
|
239
|
-
|
|
240
|
-
if [[ "$FORCE_RUN" == "true" || "$SHUTDOWN" == "false" ]]; then
|
|
241
|
-
FORCE_RUN=false
|
|
242
|
-
log INFO "Starting analysis run"
|
|
243
|
-
|
|
244
|
-
# Analyze each project directory
|
|
245
|
-
if [[ -d "$PROJECTS_DIR" ]]; then
|
|
246
|
-
for project_dir in "${PROJECTS_DIR}"/*/; do
|
|
247
|
-
[[ -d "$project_dir" ]] || continue
|
|
248
|
-
[[ "$(basename "$project_dir")" == "global" ]] && continue
|
|
249
|
-
analyze_project "$project_dir" || log WARN "Analysis failed for ${project_dir}"
|
|
250
|
-
[[ "$SHUTDOWN" == "true" ]] && break
|
|
251
|
-
done
|
|
252
|
-
fi
|
|
253
|
-
|
|
254
|
-
# Analyze global observations
|
|
255
|
-
analyze_global || log WARN "Global analysis failed"
|
|
256
|
-
|
|
257
|
-
log INFO "Analysis run complete"
|
|
258
|
-
fi
|
|
259
|
-
|
|
260
|
-
[[ "$SHUTDOWN" == "true" ]] && break
|
|
261
|
-
|
|
262
|
-
# Sleep for the configured interval
|
|
263
|
-
local interval_minutes
|
|
264
|
-
interval_minutes="$(read_config '.observer.run_interval_minutes' '5')"
|
|
265
|
-
local interval_seconds=$(( interval_minutes * 60 ))
|
|
266
|
-
|
|
267
|
-
log DEBUG "Sleeping for ${interval_minutes} minutes"
|
|
268
|
-
|
|
269
|
-
# Sleep in 1-second chunks to remain responsive to signals
|
|
270
|
-
local elapsed=0
|
|
271
|
-
while (( elapsed < interval_seconds )); do
|
|
272
|
-
sleep 1
|
|
273
|
-
(( elapsed++ )) || true
|
|
274
|
-
[[ "$SHUTDOWN" == "true" ]] && break
|
|
275
|
-
[[ "$FORCE_RUN" == "true" ]] && break
|
|
276
|
-
done
|
|
277
|
-
done
|
|
278
|
-
|
|
279
|
-
log INFO "Mulahazah observer loop exiting"
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
main "$@"
|
package/agents/observer.md
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: mulahazah-observer
|
|
3
|
-
description: Background analysis agent that reads raw tool observations and distills them into actionable instincts. Runs on a Haiku model for cost efficiency. Identifies patterns, user preferences, and recurring workflows from JSONL observation logs.
|
|
4
|
-
model: haiku
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Mulahazah Observer — Background Analysis Agent
|
|
8
|
-
|
|
9
|
-
You are the Mulahazah observer. Your job is to analyze raw tool-use observations recorded by the `observe.sh` hook and extract reusable instincts that improve future Claude Code sessions.
|
|
10
|
-
|
|
11
|
-
You run in the background, periodically. You are cost-sensitive (Haiku model). Be concise and conservative.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Inputs
|
|
16
|
-
|
|
17
|
-
You will be given:
|
|
18
|
-
1. The path to `observations.jsonl` for a project (or global observations)
|
|
19
|
-
2. The path to existing instincts (YAML files in `~/.claude/mulahazah/instincts/`)
|
|
20
|
-
3. The project metadata from `project.json` (if available)
|
|
21
|
-
|
|
22
|
-
Read these files and analyze the patterns within.
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## Pattern Detection Rules
|
|
27
|
-
|
|
28
|
-
Scan observations for these signal types, in priority order:
|
|
29
|
-
|
|
30
|
-
### 1. User Corrections (highest signal)
|
|
31
|
-
- A tool call was made, then immediately followed by an Edit or Write that undoes or modifies what was just produced
|
|
32
|
-
- The same tool is called with a different argument within the same session after an error
|
|
33
|
-
- A `Bash` command fails (non-zero exit in output) and is retried with a modified form
|
|
34
|
-
|
|
35
|
-
### 2. Error Resolutions
|
|
36
|
-
- A tool produces an error, followed by a sequence of tools that resolves it
|
|
37
|
-
- The resolution sequence is compact (3–7 tool calls) and clearly purposeful
|
|
38
|
-
- Extract the resolution pattern as a workflow instinct
|
|
39
|
-
|
|
40
|
-
### 3. Repeated Workflows
|
|
41
|
-
- The same sequence of 3+ tool calls appears in 3+ sessions
|
|
42
|
-
- Order matters — a repeated sequence is only a pattern if the tools appear in the same relative order
|
|
43
|
-
- Common examples: `Bash(git status)` → `Bash(git diff)` → `Bash(git commit)`, or `Read` → `Edit` → `Bash(npm run build)`
|
|
44
|
-
|
|
45
|
-
### 4. Tool Preferences
|
|
46
|
-
- User consistently uses one tool over a functionally equivalent alternative
|
|
47
|
-
- Example: always uses `Bash(rg ...)` via the Grep tool rather than raw `Bash(grep ...)`
|
|
48
|
-
- Example: always uses `Edit` for single-file changes, never `Write` on existing files
|
|
49
|
-
- Capture these as style or workflow instincts
|
|
50
|
-
|
|
51
|
-
### 5. Rejected Suggestions
|
|
52
|
-
- A tool call produces output, session ends shortly after without using the output
|
|
53
|
-
- Or an Edit is immediately reverted in the next tool call
|
|
54
|
-
- These indicate something to avoid — create a negative instinct (what not to do)
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## Scope Decision Guide
|
|
59
|
-
|
|
60
|
-
Assign scope based on these rules:
|
|
61
|
-
|
|
62
|
-
| Condition | Scope |
|
|
63
|
-
|-----------|-------|
|
|
64
|
-
| Pattern appears in only one project's observations | `project` |
|
|
65
|
-
| Pattern appears in 3+ different projects | `global` |
|
|
66
|
-
| Pattern involves language/framework-specific behavior | `project` (unless 3+ projects use same stack) |
|
|
67
|
-
| Pattern involves user meta-habits (git, file editing, tool choice) | `global` |
|
|
68
|
-
| Pattern involves project naming, directory structure, specific paths | `project` |
|
|
69
|
-
| Uncertain | default to `project` |
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## Instinct YAML Format
|
|
74
|
-
|
|
75
|
-
Output each new instinct as a YAML block. Do not wrap in markdown code fences — output raw YAML only, one instinct per file.
|
|
76
|
-
|
|
77
|
-
```yaml
|
|
78
|
-
id: <kebab-case-id>
|
|
79
|
-
title: <short human-readable title, max 60 chars>
|
|
80
|
-
scope: project | global
|
|
81
|
-
project_id: <12-char hash if scope=project, omit if global>
|
|
82
|
-
domain: <one of: code-style, testing, git, debugging, workflow, security, architecture>
|
|
83
|
-
confidence: <float 0.0–0.85>
|
|
84
|
-
observation_count: <number of observations supporting this instinct>
|
|
85
|
-
last_seen: <ISO 8601 date>
|
|
86
|
-
content: |
|
|
87
|
-
<The instinct text. Written as a direct instruction to Claude.
|
|
88
|
-
Max 5 sentences. No raw code snippets. No file paths unless abstract.
|
|
89
|
-
Use imperative voice. Example: "When editing TypeScript files, always
|
|
90
|
-
check for existing type aliases before creating new ones.">
|
|
91
|
-
tags:
|
|
92
|
-
- <tag1>
|
|
93
|
-
- <tag2>
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
## Confidence Rules
|
|
99
|
-
|
|
100
|
-
- **Never set confidence above 0.85** from observation data alone. Human review is required to reach 0.9.
|
|
101
|
-
- **Confidence cap is 0.9** — no instinct may ever exceed this value.
|
|
102
|
-
- Start new instincts at confidence 0.4–0.6 based on evidence strength:
|
|
103
|
-
- 3–5 supporting observations: 0.4
|
|
104
|
-
- 6–10 supporting observations: 0.55
|
|
105
|
-
- 11–20 supporting observations: 0.65
|
|
106
|
-
- 21+ supporting observations: 0.75
|
|
107
|
-
- Strong signal (user correction or error resolution): add 0.1 bonus, capped at 0.85
|
|
108
|
-
- **Decay rules** — reduce confidence by 0.05 if:
|
|
109
|
-
- The instinct was not observed in the last 30 days
|
|
110
|
-
- The instinct was observed but then contradicted (a counter-example appeared)
|
|
111
|
-
- The session count for the project drops to zero for 60+ days
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
## Domain Tags
|
|
116
|
-
|
|
117
|
-
Use exactly one domain per instinct:
|
|
118
|
-
|
|
119
|
-
| Domain | Covers |
|
|
120
|
-
|--------|--------|
|
|
121
|
-
| `code-style` | Formatting, naming, language idioms, linting preferences |
|
|
122
|
-
| `testing` | Test frameworks, coverage, test file conventions |
|
|
123
|
-
| `git` | Commit messages, branch naming, staging habits |
|
|
124
|
-
| `debugging` | Error resolution sequences, diagnostic tool preferences |
|
|
125
|
-
| `workflow` | Multi-step task sequences, tool ordering preferences |
|
|
126
|
-
| `security` | Auth patterns, secret handling, input validation |
|
|
127
|
-
| `architecture` | File structure, module boundaries, design patterns |
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## Observer Rules
|
|
132
|
-
|
|
133
|
-
1. **Be conservative.** It is better to produce no instinct than a wrong instinct. Only emit an instinct if you have clear, repeated evidence.
|
|
134
|
-
|
|
135
|
-
2. **Merge similar instincts.** If a new pattern is substantially similar to an existing instinct (same domain, same behavior), increase `observation_count` and update `confidence` on the existing instinct rather than creating a duplicate.
|
|
136
|
-
|
|
137
|
-
3. **Default to project scope.** When in doubt about scope, use `project`. Promotion to global scope should only happen when the same pattern is confirmed across multiple distinct projects.
|
|
138
|
-
|
|
139
|
-
4. **No raw code in instinct content.** Instinct content must be natural language instructions. Never embed shell commands, code snippets, or file paths in the `content` field. Use abstract descriptions instead.
|
|
140
|
-
|
|
141
|
-
5. **No hallucinated patterns.** Only describe patterns you can trace to specific observation lines. If you cannot point to concrete evidence, do not emit the instinct.
|
|
142
|
-
|
|
143
|
-
6. **Respect existing instincts.** Before creating a new instinct, check the existing instinct files. Do not duplicate, do not contradict without strong evidence.
|
|
144
|
-
|
|
145
|
-
7. **Output only YAML.** Your output must be valid YAML instinct blocks (one per instinct) separated by `---`. Do not include explanatory text, markdown, or commentary in your output — only the YAML instincts ready to be written to disk.
|
package/agents/start-observer.sh
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# start-observer.sh — Start the Mulahazah background observer
|
|
3
|
-
# Checks for an existing instance, cleans up stale PIDs, and launches observer-loop.sh.
|
|
4
|
-
|
|
5
|
-
set -euo pipefail
|
|
6
|
-
|
|
7
|
-
MULAHAZAH_DIR="${HOME}/.claude/mulahazah"
|
|
8
|
-
PID_FILE="${MULAHAZAH_DIR}/observer.pid"
|
|
9
|
-
LOG_FILE="${MULAHAZAH_DIR}/observer.log"
|
|
10
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
|
-
LOOP_SCRIPT="${SCRIPT_DIR}/observer-loop.sh"
|
|
12
|
-
|
|
13
|
-
# ---------------------------------------------------------------------------
|
|
14
|
-
# Helpers
|
|
15
|
-
# ---------------------------------------------------------------------------
|
|
16
|
-
print_status() {
|
|
17
|
-
local pid="$1"
|
|
18
|
-
echo "Mulahazah observer is running (PID ${pid})"
|
|
19
|
-
echo ""
|
|
20
|
-
echo " Force immediate analysis: kill -USR1 ${pid}"
|
|
21
|
-
echo " Stop observer: kill ${pid}"
|
|
22
|
-
echo " View logs: tail -f ${LOG_FILE}"
|
|
23
|
-
echo " PID file: ${PID_FILE}"
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
# ---------------------------------------------------------------------------
|
|
27
|
-
# Validate dependencies
|
|
28
|
-
# ---------------------------------------------------------------------------
|
|
29
|
-
if ! command -v jq &>/dev/null; then
|
|
30
|
-
echo "Error: jq is required but not installed." >&2
|
|
31
|
-
exit 1
|
|
32
|
-
fi
|
|
33
|
-
|
|
34
|
-
if ! command -v claude &>/dev/null; then
|
|
35
|
-
echo "Error: claude CLI is required but not installed." >&2
|
|
36
|
-
exit 1
|
|
37
|
-
fi
|
|
38
|
-
|
|
39
|
-
if [[ ! -f "$LOOP_SCRIPT" ]]; then
|
|
40
|
-
echo "Error: observer-loop.sh not found at ${LOOP_SCRIPT}" >&2
|
|
41
|
-
exit 1
|
|
42
|
-
fi
|
|
43
|
-
|
|
44
|
-
# ---------------------------------------------------------------------------
|
|
45
|
-
# Check for existing running instance
|
|
46
|
-
# ---------------------------------------------------------------------------
|
|
47
|
-
if [[ -f "$PID_FILE" ]]; then
|
|
48
|
-
EXISTING_PID="$(cat "$PID_FILE" 2>/dev/null || true)"
|
|
49
|
-
|
|
50
|
-
if [[ -n "$EXISTING_PID" ]] && kill -0 "$EXISTING_PID" 2>/dev/null; then
|
|
51
|
-
# Process is alive
|
|
52
|
-
echo "Mulahazah observer is already running."
|
|
53
|
-
echo ""
|
|
54
|
-
print_status "$EXISTING_PID"
|
|
55
|
-
exit 0
|
|
56
|
-
else
|
|
57
|
-
# Stale PID file — process is gone
|
|
58
|
-
echo "Cleaning up stale PID file (PID ${EXISTING_PID:-unknown} is no longer running)"
|
|
59
|
-
rm -f "$PID_FILE"
|
|
60
|
-
fi
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
# ---------------------------------------------------------------------------
|
|
64
|
-
# Ensure Mulahazah directory structure exists
|
|
65
|
-
# ---------------------------------------------------------------------------
|
|
66
|
-
mkdir -p "${MULAHAZAH_DIR}/projects"
|
|
67
|
-
mkdir -p "${MULAHAZAH_DIR}/instincts/global"
|
|
68
|
-
|
|
69
|
-
# ---------------------------------------------------------------------------
|
|
70
|
-
# Initialize config.json if it doesn't exist
|
|
71
|
-
# ---------------------------------------------------------------------------
|
|
72
|
-
CONFIG_FILE="${MULAHAZAH_DIR}/config.json"
|
|
73
|
-
if [[ ! -f "$CONFIG_FILE" ]]; then
|
|
74
|
-
# Check if a repo-level config exists next to this script's parent
|
|
75
|
-
REPO_CONFIG="$(dirname "$SCRIPT_DIR")/config.json"
|
|
76
|
-
if [[ -f "$REPO_CONFIG" ]]; then
|
|
77
|
-
cp "$REPO_CONFIG" "$CONFIG_FILE"
|
|
78
|
-
echo "Initialized config from ${REPO_CONFIG}"
|
|
79
|
-
else
|
|
80
|
-
cat > "$CONFIG_FILE" <<'EOF'
|
|
81
|
-
{
|
|
82
|
-
"version": "2.0",
|
|
83
|
-
"observer": {
|
|
84
|
-
"enabled": true,
|
|
85
|
-
"run_interval_minutes": 5,
|
|
86
|
-
"min_observations_to_analyze": 20,
|
|
87
|
-
"model": "haiku"
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
EOF
|
|
91
|
-
echo "Created default config at ${CONFIG_FILE}"
|
|
92
|
-
fi
|
|
93
|
-
fi
|
|
94
|
-
|
|
95
|
-
# ---------------------------------------------------------------------------
|
|
96
|
-
# Launch observer-loop.sh in background with nohup
|
|
97
|
-
# ---------------------------------------------------------------------------
|
|
98
|
-
nohup bash "$LOOP_SCRIPT" >> "$LOG_FILE" 2>&1 &
|
|
99
|
-
OBSERVER_PID=$!
|
|
100
|
-
|
|
101
|
-
# Write PID file
|
|
102
|
-
printf '%d\n' "$OBSERVER_PID" > "$PID_FILE"
|
|
103
|
-
|
|
104
|
-
# Brief pause to confirm the process started
|
|
105
|
-
sleep 1
|
|
106
|
-
if ! kill -0 "$OBSERVER_PID" 2>/dev/null; then
|
|
107
|
-
echo "Error: observer-loop.sh failed to start. Check logs:" >&2
|
|
108
|
-
echo " ${LOG_FILE}" >&2
|
|
109
|
-
rm -f "$PID_FILE"
|
|
110
|
-
exit 1
|
|
111
|
-
fi
|
|
112
|
-
|
|
113
|
-
echo "Mulahazah observer started."
|
|
114
|
-
echo ""
|
|
115
|
-
print_status "$OBSERVER_PID"
|