pulse-framework-cli 0.4.2 → 0.4.4

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.
@@ -66,7 +66,7 @@ function registerDoctorCommand(program) {
66
66
  }
67
67
  }
68
68
  // ════════════════════════════════════════════════════════════════════════
69
- // Preset-Verletzungen explizit hinzufügen
69
+ // Add preset limit violations explicitly
70
70
  // ════════════════════════════════════════════════════════════════════════
71
71
  const scope = (0, briefing_js_1.calculateScopeCheck)(config, scan.stats);
72
72
  if (scope.exceeded) {
@@ -38,7 +38,7 @@ function registerResetCommand(program) {
38
38
  }
39
39
  }
40
40
  // ══════════════════════════════════════════════════════════════════════
41
- // Zeige betroffene Commits
41
+ // Show affected commits
42
42
  // ══════════════════════════════════════════════════════════════════════
43
43
  const recentLog = await (0, git_js_1.gitLogOneline)(repoRoot, numCommits + 2);
44
44
  const logLines = recentLog.split("\n").filter((l) => l.trim());
@@ -57,7 +57,7 @@ function registerResetCommand(program) {
57
57
  // eslint-disable-next-line no-console
58
58
  console.log("");
59
59
  // ══════════════════════════════════════════════════════════════════════
60
- // Reset-Modus wählen
60
+ // Choose reset mode
61
61
  // ══════════════════════════════════════════════════════════════════════
62
62
  let mode = "mixed";
63
63
  if (opts.soft) {
@@ -75,7 +75,7 @@ function registerResetCommand(program) {
75
75
  mode = await (0, input_js_1.promptSelect)("Reset mode", choices, "mixed");
76
76
  }
77
77
  // ══════════════════════════════════════════════════════════════════════
78
- // Letzte Bestätigung bei Hard Reset
78
+ // Final confirmation for hard reset
79
79
  // ══════════════════════════════════════════════════════════════════════
80
80
  if (mode === "hard" && !opts.yes) {
81
81
  // eslint-disable-next-line no-console
@@ -88,7 +88,7 @@ function registerResetCommand(program) {
88
88
  }
89
89
  }
90
90
  // ══════════════════════════════════════════════════════════════════════
91
- // Git Reset ausführen
91
+ // Execute git reset
92
92
  // ══════════════════════════════════════════════════════════════════════
93
93
  const resetArg = `HEAD~${numCommits}`;
94
94
  const modeArg = mode === "mixed" ? "" : `--${mode}`;
@@ -102,14 +102,14 @@ function registerResetCommand(program) {
102
102
  process.exit(1);
103
103
  }
104
104
  // ══════════════════════════════════════════════════════════════════════
105
- // Erfolgsmeldung
105
+ // Success message
106
106
  // ══════════════════════════════════════════════════════════════════════
107
107
  const newLog = await (0, git_js_1.gitLogOneline)(repoRoot, 1);
108
108
  // eslint-disable-next-line no-console
109
109
  console.log(`✅ Reset successful!`);
110
110
  // eslint-disable-next-line no-console
111
111
  console.log(`📍 New HEAD: ${newLog}\n`);
112
- // Hinweise
112
+ // Tips
113
113
  if (mode === "soft" || mode === "mixed") {
114
114
  // eslint-disable-next-line no-console
115
115
  console.log(`💡 Tip: Changes are still there.`);
@@ -46,15 +46,15 @@ function registerRunCommand(program) {
46
46
  program
47
47
  .command("run")
48
48
  .description("Combined workflow: Start → Watch → Checkpoints → Review")
49
- .option("-t, --template <id>", "Vorlage: feature, bugfix, refactor, concept, analyze, review")
49
+ .option("-t, --template <id>", "Template: feature, bugfix, refactor, concept, analyze, review")
50
50
  .option("--minutes <n>", "Minutes between checkpoint reminders")
51
51
  .option("--no-watch", "Don't start watcher")
52
- .option("--action <text>", "ACTION direkt angeben")
53
- .option("-C, --clipboard", "Prompt in Zwischenablage kopieren")
52
+ .option("--action <text>", "Provide ACTION directly")
53
+ .option("-C, --clipboard", "Copy prompt to clipboard")
54
54
  .action(async (opts) => {
55
55
  const repoRoot = await (0, paths_js_1.findRepoRoot)(process.cwd());
56
56
  if (!repoRoot)
57
- throw new Error("Nicht in einem Git-Repository.");
57
+ throw new Error("Not in a git repository.");
58
58
  const [state, config] = await Promise.all([(0, artifacts_js_1.loadState)(repoRoot), (0, config_js_1.loadConfig)(repoRoot)]);
59
59
  // Use preset checkpoint interval if not specified
60
60
  const minutes = opts.minutes
@@ -76,17 +76,17 @@ function registerRunCommand(program) {
76
76
  // ════════════════════════════════════════════════════════════════════════
77
77
  // eslint-disable-next-line no-console
78
78
  console.log(`━━━ PHASE 1: Prompt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
79
- // Template auswählen
79
+ // Select template
80
80
  let template = opts.template ? (0, prompts_js_1.getTemplateById)(opts.template) : undefined;
81
81
  if (!template && !opts.action) {
82
82
  const choices = prompts_js_1.PROMPT_TEMPLATES.map((t) => ({
83
83
  value: t.id,
84
84
  label: `${t.name} - ${t.description}`,
85
85
  }));
86
- const selectedId = await (0, input_js_1.promptSelect)("📋 Vorlage wählen", choices, "feature");
86
+ const selectedId = await (0, input_js_1.promptSelect)("📋 Choose template", choices, "feature");
87
87
  template = (0, prompts_js_1.getTemplateById)(selectedId);
88
88
  }
89
- // 6-Elemente sammeln
89
+ // Collect the 6 elements
90
90
  const el = {
91
91
  role: template?.defaults.role,
92
92
  context: template?.defaults.context,
@@ -95,14 +95,14 @@ function registerRunCommand(program) {
95
95
  };
96
96
  const layer = template?.layer ?? state.profile;
97
97
  if (!el.action?.trim()) {
98
- el.action = await (0, input_js_1.promptText)("⚡ ACTION (Was soll gemacht werden?)", "");
98
+ el.action = await (0, input_js_1.promptText)("⚡ ACTION (what should be built?)", "");
99
99
  }
100
100
  if (!el.context?.trim()) {
101
- el.context = await (0, input_js_1.promptText)("📍 KONTEXT (Projekt, Stack)", "");
101
+ el.context = await (0, input_js_1.promptText)("📍 CONTEXT (project, stack)", "");
102
102
  }
103
- // Prompt generieren
103
+ // Generate prompt
104
104
  const prompt = (0, prompts_js_1.renderSixElementPrompt)(layer, el);
105
- // Artefakt speichern
105
+ // Save artifact
106
106
  const ts = (0, artifacts_js_1.timestampId)();
107
107
  const filename = `${ts}-run.md`;
108
108
  const content = [
@@ -110,7 +110,7 @@ function registerRunCommand(program) {
110
110
  ``,
111
111
  `- Profile: **${presetProfile}**`,
112
112
  `- Layer: **${layer}**`,
113
- template ? `- Vorlage: **${template.name}**` : "",
113
+ template ? `- Template: **${template.name}**` : "",
114
114
  `- Checkpoint interval: **${minutes} min**`,
115
115
  ``,
116
116
  `## Prompt`,
@@ -126,7 +126,7 @@ function registerRunCommand(program) {
126
126
  // eslint-disable-next-line no-console
127
127
  console.log(`✅ Template: ${template?.name ?? "custom"}`);
128
128
  // eslint-disable-next-line no-console
129
- console.log(`✅ Artefakt: ${artifactPath}`);
129
+ console.log(`✅ Artifact: ${artifactPath}`);
130
130
  // Clipboard
131
131
  if (opts.clipboard) {
132
132
  const clipMsg = await (0, clipboard_js_1.copyAndNotify)(prompt);
@@ -148,19 +148,19 @@ function registerRunCommand(program) {
148
148
  // ════════════════════════════════════════════════════════════════════════
149
149
  if (opts.watch === false) {
150
150
  // eslint-disable-next-line no-console
151
- console.log(`━━━ PHASE 2: Übersprungen ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
151
+ console.log(`━━━ PHASE 2: Skipped ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
152
152
  // eslint-disable-next-line no-console
153
153
  console.log("Watcher not started (--no-watch).\n");
154
154
  // eslint-disable-next-line no-console
155
155
  console.log("💡 Next steps:");
156
156
  // eslint-disable-next-line no-console
157
- console.log(" 1. Prompt in Cursor einfügen");
157
+ console.log(" 1. Paste the prompt into Cursor");
158
158
  // eslint-disable-next-line no-console
159
- console.log(" 2. `pulse checkpoint` alle 5-10 Min");
159
+ console.log(" 2. Run `pulse checkpoint` every 5-10 min");
160
160
  // eslint-disable-next-line no-console
161
- console.log(" 3. Bei Problemen: `pulse escalate`");
161
+ console.log(" 3. If stuck: `pulse escalate`");
162
162
  // eslint-disable-next-line no-console
163
- console.log(" 4. Am Ende: `pulse review`\n");
163
+ console.log(" 4. At the end: `pulse review`\n");
164
164
  return;
165
165
  }
166
166
  // eslint-disable-next-line no-console
@@ -170,12 +170,12 @@ function registerRunCommand(program) {
170
170
  // eslint-disable-next-line no-console
171
171
  console.log(`📍 Watcher running... (Ctrl+C to stop)\n`);
172
172
  // eslint-disable-next-line no-console
173
- console.log(` 1. Kopiere den Prompt oben in Cursor`);
173
+ console.log(` 1. Paste the prompt above into Cursor`);
174
174
  // eslint-disable-next-line no-console
175
- console.log(` 2. Arbeite los`);
175
+ console.log(` 2. Start working`);
176
176
  // eslint-disable-next-line no-console
177
- console.log(` 3. Ctrl+C wenn fertig\n`);
178
- await (0, notifications_js_1.notify)(config.notifications, "Pulse Run gestartet", `Checkpoint reminder every ${minutes} min. Ctrl+C to exit.`);
177
+ console.log(` 3. Ctrl+C when done\n`);
178
+ await (0, notifications_js_1.notify)(config.notifications, "Pulse Run started", `Checkpoint reminder every ${minutes} min. Ctrl+C to exit.`);
179
179
  // Update state
180
180
  state.lastCheckpointAt = new Date().toISOString();
181
181
  await (0, artifacts_js_1.saveState)(repoRoot, state);
@@ -200,11 +200,11 @@ function registerRunCommand(program) {
200
200
  // eslint-disable-next-line no-console
201
201
  console.log(`└${"─".repeat(58)}┘`);
202
202
  // eslint-disable-next-line no-console
203
- console.log(` Zeit: ${new Date().toLocaleTimeString()}`);
203
+ console.log(` Time: ${new Date().toLocaleTimeString()}`);
204
204
  // eslint-disable-next-line no-console
205
- console.log(` Status: Uncommitted Changes vorhanden`);
205
+ console.log(` Status: uncommitted changes present`);
206
206
  // eslint-disable-next-line no-console
207
- console.log(` → pulse checkpoint -m 'deine message'\n`);
207
+ console.log(` → pulse checkpoint -m 'your message'\n`);
208
208
  }
209
209
  else {
210
210
  // eslint-disable-next-line no-console
@@ -217,15 +217,15 @@ function registerRunCommand(program) {
217
217
  const cleanup = async (signal) => {
218
218
  clearInterval(interval);
219
219
  // eslint-disable-next-line no-console
220
- console.log(`\n\n━━━ PHASE 3: Abschluss ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
220
+ console.log(`\n\n━━━ PHASE 3: Wrap-up ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
221
221
  // eslint-disable-next-line no-console
222
- console.log(`🛑 ${signal} empfangen - Beende Pulse Run...\n`);
222
+ console.log(`🛑 Received ${signal} - stopping Pulse Run...\n`);
223
223
  // Check final status
224
224
  const status = await (0, git_js_1.gitStatusPorcelain)(repoRoot);
225
225
  const dirty = status.trim().length > 0;
226
226
  if (dirty) {
227
227
  // eslint-disable-next-line no-console
228
- console.log("📝 Uncommitted Changes gefunden:\n");
228
+ console.log("📝 Uncommitted changes found:\n");
229
229
  const stat = await (0, git_js_1.gitDiffStat)(repoRoot);
230
230
  // eslint-disable-next-line no-console
231
231
  console.log(stat);
@@ -243,25 +243,25 @@ function registerRunCommand(program) {
243
243
  }
244
244
  else {
245
245
  // eslint-disable-next-line no-console
246
- console.log("✨ Keine uncommitted Changes.\n");
246
+ console.log("✨ No uncommitted changes.\n");
247
247
  }
248
248
  // Offer review
249
249
  const doReview = await (0, input_js_1.promptConfirm)("Create review?", dirty);
250
250
  if (doReview) {
251
251
  // eslint-disable-next-line no-console
252
- console.log("\n💡 Führe aus: pulse review\n");
252
+ console.log("\n💡 Run: pulse review\n");
253
253
  }
254
254
  // Summary
255
255
  // eslint-disable-next-line no-console
256
256
  console.log(`┌${"─".repeat(58)}┐`);
257
257
  // eslint-disable-next-line no-console
258
- console.log(`│ 👋 Pulse Run beendet${" ".repeat(37)}│`);
258
+ console.log(`│ 👋 Pulse Run finished${" ".repeat(35)}│`);
259
259
  // eslint-disable-next-line no-console
260
260
  console.log(`│ │`);
261
261
  // eslint-disable-next-line no-console
262
262
  console.log(`│ Checkpoints: ${checkpointCount}${" ".repeat(43 - String(checkpointCount).length)}│`);
263
263
  // eslint-disable-next-line no-console
264
- console.log(`│ Artefakt: .pulse/pulses/${filename}${" ".repeat(Math.max(0, 32 - filename.length))}│`);
264
+ console.log(`│ Artifact: .pulse/pulses/${filename}${" ".repeat(Math.max(0, 32 - filename.length))}│`);
265
265
  // eslint-disable-next-line no-console
266
266
  console.log(`└${"─".repeat(58)}┘\n`);
267
267
  process.exit(0);
@@ -75,13 +75,39 @@ fi
75
75
  `, "utf8");
76
76
  await ensureExecutable(postCommit);
77
77
  await promises_1.default.writeFile(prePush, `#!/bin/sh
78
- set -e
79
-
80
78
  # Pulse safeguard: never push without explicit permission.
81
79
  # Allow push explicitly by running:
82
80
  # PULSE_ALLOW_PUSH=1 git push ...
83
81
 
84
- pulse doctor --hook pre-push
82
+ if [ "$PULSE_SKIP_HOOKS" = "1" ]; then
83
+ exit 0
84
+ fi
85
+
86
+ if [ "$PULSE_ALLOW_PUSH" != "1" ]; then
87
+ echo "PULSE safeguard: push blocked. Set PULSE_ALLOW_PUSH=1 for an explicit push."
88
+ exit 1
89
+ fi
90
+
91
+ # Run doctor check if pulse CLI is available
92
+ if command -v pulse >/dev/null 2>&1; then
93
+ pulse doctor --hook pre-push
94
+ EXIT_CODE=$?
95
+ elif command -v pulse-framework >/dev/null 2>&1; then
96
+ pulse-framework doctor --hook pre-push
97
+ EXIT_CODE=$?
98
+ else
99
+ EXIT_CODE=0
100
+ fi
101
+
102
+ # Only block on CRITICAL (exit 2), allow warnings (exit 1) - consistent with pre-commit
103
+ if [ $EXIT_CODE -eq 2 ]; then
104
+ echo ""
105
+ echo "❌ Push blocked by PULSE (critical findings)"
106
+ echo " Fix issues or use: PULSE_SKIP_HOOKS=1 git push ..."
107
+ exit 2
108
+ fi
109
+
110
+ exit 0
85
111
  `, "utf8");
86
112
  await ensureExecutable(prePush);
87
113
  // eslint-disable-next-line no-console
package/dist/lib/input.js CHANGED
@@ -37,7 +37,7 @@ async function promptSelect(label, choices, defaultValue) {
37
37
  });
38
38
  // eslint-disable-next-line no-console
39
39
  console.log("");
40
- const ans = await rl.question("Nummer wählen: ");
40
+ const ans = await rl.question("Enter number: ");
41
41
  const num = parseInt(ans.trim(), 10);
42
42
  if (num >= 1 && num <= choices.length) {
43
43
  const choice = choices[num - 1];
@@ -65,12 +65,13 @@ async function promptSelect(label, choices, defaultValue) {
65
65
  async function promptConfirm(label, defaultYes = false) {
66
66
  const rl = promises_1.default.createInterface({ input: process.stdin, output: process.stdout });
67
67
  try {
68
- const hint = defaultYes ? "(J/n)" : "(j/N)";
68
+ const hint = defaultYes ? "(Y/n)" : "(y/N)";
69
69
  const ans = await rl.question(`${label} ${hint}: `);
70
70
  const v = ans.trim().toLowerCase();
71
- if (v === "j" || v === "y" || v === "ja" || v === "yes")
71
+ // Accept a few common variants (English + legacy German inputs)
72
+ if (v === "y" || v === "yes" || v === "j" || v === "ja")
72
73
  return true;
73
- if (v === "n" || v === "nein" || v === "no")
74
+ if (v === "n" || v === "no" || v === "nein")
74
75
  return false;
75
76
  return defaultYes;
76
77
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pulse-framework-cli",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "Pulse Framework CLI – Guardrails, checkpoints, and escalation for AI-assisted development.",
5
5
  "author": "Manuel Fuß <kontakt@manuel-fuss.de>",
6
6
  "license": "MIT",
@@ -154,6 +154,52 @@
154
154
  # 4. ESTIMATE the effort:
155
155
  # "Estimated effort: [X] minutes. Should I start?"
156
156
 
157
+ # ┌─────────────────────────────────────────────────────────────────────────────┐
158
+ # │ 🔧 MCP TOOL TRIGGERS (WHEN TO CALL) │
159
+ # └─────────────────────────────────────────────────────────────────────────────┘
160
+
161
+ # pulse_status → FIRST action of every response
162
+ # pulse_doctor → AFTER any file edit/create/delete
163
+ # pulse_checkpoint → WHEN >10 min since last checkpoint (just do it)
164
+ # pulse_run → WHEN user gives multi-step task (>3 steps)
165
+ # pulse_escalate → WHEN 2-3 failed attempts OR error you don't understand
166
+ # pulse_correct → WHEN user says "wrong", "not what I meant", "stop"
167
+ # pulse_review → BEFORE saying "done", creating PR, or merging
168
+ # pulse_learn → AFTER solving a non-trivial problem (document what worked!)
169
+ # pulse_reset → WHEN pulse_doctor shows loop signal
170
+
171
+ # IMPORTANT: Call these ACTIVELY, not just when user asks!
172
+ # - After success: pulse_learn (build knowledge)
173
+ # - Before "done": pulse_review (final check)
174
+ # - On problems: pulse_escalate (don't keep trying)
175
+
176
+ # ┌─────────────────────────────────────────────────────────────────────────────┐
177
+ # │ 📝 CHANGELOG PROTOCOL (MANDATORY) │
178
+ # └─────────────────────────────────────────────────────────────────────────────┘
179
+
180
+ # EVERY significant change MUST be documented in CHANGELOG.md
181
+ #
182
+ # WHEN to update:
183
+ # - New feature added
184
+ # - Bug fixed
185
+ # - Breaking change
186
+ # - Behavior changed
187
+ # - After each session with multiple changes
188
+ #
189
+ # FORMAT (Keep a Changelog style):
190
+ # ## [version] (YYYY-MM-DD)
191
+ # ### Added - for new features
192
+ # ### Changed - for changes in existing functionality
193
+ # ### Fixed - for bug fixes
194
+ # ### Removed - for removed features
195
+ # ### Security - for security fixes
196
+ #
197
+ # IMPORTANT:
198
+ # - Update CHANGELOG.md BEFORE committing significant changes
199
+ # - Include specific details (what, why)
200
+ # - Reference issue numbers if applicable
201
+ # - Keep the project alive with good documentation!
202
+
157
203
  # ┌─────────────────────────────────────────────────────────────────────────────┐
158
204
  # │ 📦 PULSE PUBLISHING PROTOCOL │
159
205
  # └─────────────────────────────────────────────────────────────────────────────┘
@@ -53,18 +53,22 @@ WHEN: pulse_status shows >10 min since checkpoint
53
53
  WHAT: "Should I create a checkpoint?"
54
54
  ```
55
55
 
56
- ## 🔴 AUTOMATIC ACTIONS
57
-
58
- | Situation | Action |
59
- |-----------|--------|
60
- | Start of response | → `pulse_status` (once) |
61
- | Code changed | → `pulse_doctor` |
62
- | >10 min since checkpoint | → Recommend checkpoint |
63
- | >15 min since checkpoint | → **Checkpoint URGENT** |
64
- | >30 min autonomous | → **STOP + ask user** |
65
- | 2-3 failed attempts | → **STOP + `pulse_escalate`** |
66
- | DELETE operation | → **Get user confirmation** |
67
- | Loop detected | → **STOP + `pulse_escalate`** |
56
+ ## 🔴 AUTOMATIC ACTIONS (MANDATORY)
57
+
58
+ | Situation | Action | Example |
59
+ |-----------|--------|---------|
60
+ | Start of response | → `pulse_status` | Every message |
61
+ | Code changed | → `pulse_doctor` | After any edit/create/delete |
62
+ | >10 min since checkpoint | → `pulse_checkpoint` | Just do it, don't ask |
63
+ | >30 min autonomous | → **STOP + ask user** | "I've been working 30 min, should I continue?" |
64
+ | 2-3 failed attempts | → `pulse_escalate` | Build fails twice, test fails twice |
65
+ | Error you don't understand | → `pulse_escalate` | Cryptic error message |
66
+ | User says "that's wrong" | → `pulse_correct` | Course correction |
67
+ | Task completed successfully | → `pulse_learn` | "What did I learn from this?" |
68
+ | Before "done" / PR / merge | → `pulse_review` | Final checklist |
69
+ | New multi-step task | → `pulse_run` | User gives complex task |
70
+ | Loop signal detected | → `pulse_reset` | Doctor shows loop warning |
71
+ | DELETE operation | → **Get user confirmation** | "May I delete X?" |
68
72
 
69
73
  ## 🔴 SAFEGUARDS (non-negotiable)
70
74
 
@@ -103,19 +107,29 @@ After 2-3 failed attempts:
103
107
  - Error message
104
108
  3. **WAIT** for user instruction
105
109
 
106
- ## MCP Tools
110
+ ## After Success (IMPORTANT!)
107
111
 
108
- | Tool | When |
109
- |------|------|
110
- | `pulse_status` | **Once per response** (at start) |
111
- | `pulse_doctor` | **After code changes** |
112
- | `pulse_checkpoint` | After 5-10 min / on recommendation |
113
- | `pulse_run` | At start of new tasks |
114
- | `pulse_escalate` | On problems, loop |
115
- | `pulse_correct` | On course correction |
116
- | `pulse_review` | At end / before merge |
117
- | `pulse_learn` | After solved problems |
118
- | `pulse_reset` | On loop, reset |
112
+ When you successfully solve a non-trivial problem:
113
+
114
+ 1. **Call `pulse_learn`** to document:
115
+ - What the problem was
116
+ - What solution worked
117
+ - Any rule/pattern to remember
118
+ 2. This builds institutional knowledge for future sessions
119
+
120
+ ## MCP Tools - WHEN TO CALL
121
+
122
+ | Tool | Trigger (MANDATORY) |
123
+ |------|---------------------|
124
+ | `pulse_status` | **FIRST action** of every response |
125
+ | `pulse_doctor` | **AFTER** any file edit/create/delete |
126
+ | `pulse_checkpoint` | **WHEN** >10 min since last checkpoint |
127
+ | `pulse_run` | **WHEN** user gives multi-step task (>3 steps) |
128
+ | `pulse_escalate` | **WHEN** 2-3 failed attempts OR error you don't understand |
129
+ | `pulse_correct` | **WHEN** user says "wrong", "not what I meant", "stop" |
130
+ | `pulse_review` | **BEFORE** saying "done", creating PR, or merging |
131
+ | `pulse_learn` | **AFTER** solving a non-trivial problem (document what worked) |
132
+ | `pulse_reset` | **WHEN** `pulse_doctor` shows loop signal |
119
133
 
120
134
  ## Example Flow
121
135
 
@@ -142,3 +156,4 @@ Agent:
142
156
  - Call the tools ACTIVELY, not only when user asks
143
157
  - When uncertain: STOP and ASK
144
158
  - The safeguards ALWAYS apply, even if user argues against them
159
+ - **ALWAYS update CHANGELOG.md** after significant changes (features, fixes, changes)