loopforge 1.1.1 → 1.3.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.
Files changed (66) hide show
  1. package/dist/cli.d.ts +1 -1
  2. package/dist/cli.js +36 -183
  3. package/dist/cli.js.map +1 -1
  4. package/dist/engine.d.ts.map +1 -1
  5. package/dist/engine.js +2 -2
  6. package/dist/engine.js.map +1 -1
  7. package/dist/generate-schema.js +56 -4
  8. package/dist/generate-schema.js.map +1 -1
  9. package/dist/index.d.ts +17 -7
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +17 -7
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp/server.d.ts +14 -0
  14. package/dist/mcp/server.d.ts.map +1 -0
  15. package/dist/mcp/server.js +93 -0
  16. package/dist/mcp/server.js.map +1 -0
  17. package/dist/mcp/session.d.ts +57 -0
  18. package/dist/mcp/session.d.ts.map +1 -0
  19. package/dist/mcp/session.js +177 -0
  20. package/dist/mcp/session.js.map +1 -0
  21. package/dist/mcp/tools.d.ts +108 -0
  22. package/dist/mcp/tools.d.ts.map +1 -0
  23. package/dist/mcp/tools.js +191 -0
  24. package/dist/mcp/tools.js.map +1 -0
  25. package/dist/mcp-server.d.ts +12 -0
  26. package/dist/mcp-server.d.ts.map +1 -0
  27. package/dist/mcp-server.js +14 -0
  28. package/dist/mcp-server.js.map +1 -0
  29. package/dist/policy.d.ts +8 -0
  30. package/dist/policy.d.ts.map +1 -1
  31. package/dist/policy.js +7 -0
  32. package/dist/policy.js.map +1 -1
  33. package/dist/protocol.d.ts +68 -1
  34. package/dist/protocol.d.ts.map +1 -1
  35. package/dist/protocol.js +9 -1
  36. package/dist/protocol.js.map +1 -1
  37. package/dist/runtime.d.ts +57 -0
  38. package/dist/runtime.d.ts.map +1 -0
  39. package/dist/runtime.js +414 -0
  40. package/dist/runtime.js.map +1 -0
  41. package/dist/tests/_helpers.d.ts +25 -0
  42. package/dist/tests/_helpers.d.ts.map +1 -0
  43. package/dist/tests/_helpers.js +47 -0
  44. package/dist/tests/_helpers.js.map +1 -0
  45. package/dist/tests/generate-schema.test.js +2 -2
  46. package/dist/tests/generate-schema.test.js.map +1 -1
  47. package/dist/tests/mcp.test.d.ts +7 -0
  48. package/dist/tests/mcp.test.d.ts.map +1 -0
  49. package/dist/tests/mcp.test.js +212 -0
  50. package/dist/tests/mcp.test.js.map +1 -0
  51. package/dist/tests/replay.test.js +69 -41
  52. package/dist/tests/replay.test.js.map +1 -1
  53. package/dist/tests/runtime.test.d.ts +7 -0
  54. package/dist/tests/runtime.test.d.ts.map +1 -0
  55. package/dist/tests/runtime.test.js +323 -0
  56. package/dist/tests/runtime.test.js.map +1 -0
  57. package/loop_policy.json +7 -0
  58. package/package.json +8 -6
  59. package/skills/perception/SKILL.md +186 -0
  60. package/skills/prompt-techniques/SKILL.md +52 -0
  61. package/skills/prompt-techniques/references/chain-of-thought.md +207 -0
  62. package/skills/prompt-techniques/references/few-shot.md +174 -0
  63. package/skills/prompt-techniques/references/least-to-most.md +182 -0
  64. package/skills/prompt-techniques/references/step-back.md +160 -0
  65. package/skills/prompt-techniques/references/tree-of-thought.md +191 -0
  66. package/skills/prompt-techniques/references/zero-shot.md +97 -0
@@ -0,0 +1,323 @@
1
+ /** LoopForge — Runtime tests (v1.2).
2
+ *
3
+ * Tests: LoopRuntime lifecycle, run() convenience function,
4
+ * heartbeat, timeout, stall, stop(), error handling.
5
+ */
6
+ import { describe, it } from "node:test";
7
+ import assert from "node:assert/strict";
8
+ import { LoopRuntime, run } from "../runtime.js";
9
+ import { RuntimeStatus, makeSelfEvaluation } from "../protocol.js";
10
+ // ═══════════════════════════════════════════════════════════════════════════
11
+ // Helpers
12
+ // ═══════════════════════════════════════════════════════════════════════════
13
+ function makeAgentOutput(opts = {}) {
14
+ const se = makeSelfEvaluation({
15
+ success: true,
16
+ output_summary: "Task completed successfully.",
17
+ constraint_violations: [],
18
+ should_continue: true,
19
+ ...opts,
20
+ });
21
+ return [
22
+ "## Result",
23
+ "",
24
+ "I completed the task as requested.",
25
+ "",
26
+ "---loopforge-eval",
27
+ JSON.stringify(se, null, 2),
28
+ "---end-loopforge-eval",
29
+ "",
30
+ ].join("\n");
31
+ }
32
+ function makeFailingOutput(violations) {
33
+ return makeAgentOutput({
34
+ success: false,
35
+ output_summary: "Task partially completed.",
36
+ constraint_violations: violations,
37
+ should_continue: true,
38
+ });
39
+ }
40
+ function mockExecutor(responses) {
41
+ let idx = 0;
42
+ return async (_prompt, _ctx) => {
43
+ if (idx >= responses.length) {
44
+ throw new Error("mockExecutor: no more responses");
45
+ }
46
+ return responses[idx++];
47
+ };
48
+ }
49
+ function slowExecutor(responses, delayMs) {
50
+ let idx = 0;
51
+ return async (_prompt, _ctx) => {
52
+ if (idx >= responses.length) {
53
+ throw new Error("slowExecutor: no more responses");
54
+ }
55
+ await new Promise((r) => setTimeout(r, delayMs));
56
+ return responses[idx++];
57
+ };
58
+ }
59
+ // ═══════════════════════════════════════════════════════════════════════════
60
+ // run() convenience function
61
+ // ═══════════════════════════════════════════════════════════════════════════
62
+ describe("run() — convenience function", () => {
63
+ it("completes 3-round loop with auto-generated loopId", async () => {
64
+ const responses = [
65
+ makeAgentOutput({ should_continue: true }),
66
+ makeAgentOutput({ should_continue: true }),
67
+ makeAgentOutput({ should_continue: false }),
68
+ ];
69
+ const result = await run({
70
+ task: "Test task for minimal config",
71
+ execute: mockExecutor(responses),
72
+ maxRounds: 10,
73
+ });
74
+ assert.equal(result.stopReason, "task_complete");
75
+ assert.equal(result.success, true);
76
+ assert.equal(result.roundsCompleted, 3);
77
+ assert.equal(result.qualityTrajectory.length, 3);
78
+ // All rounds should have quality 5 (success + no violations)
79
+ for (const q of result.qualityTrajectory) {
80
+ assert.equal(q, 5);
81
+ }
82
+ });
83
+ it("stops on task_complete when should_continue=false", async () => {
84
+ const result = await run({
85
+ task: "Test task complete",
86
+ execute: mockExecutor([
87
+ makeAgentOutput({ should_continue: false }),
88
+ ]),
89
+ maxRounds: 10,
90
+ });
91
+ assert.equal(result.stopReason, "task_complete");
92
+ assert.equal(result.roundsCompleted, 1);
93
+ });
94
+ it("stops on max_rounds when agent always continues", async () => {
95
+ // Use ascending quality to avoid circuit breaker (flat 5,5,5 fires breaker)
96
+ const responses = [
97
+ makeAgentOutput({ success: false, constraint_violations: [], should_continue: true }), // quality 1
98
+ makeAgentOutput({ success: true, constraint_violations: [], should_continue: true }), // quality 5
99
+ makeAgentOutput({ success: true, constraint_violations: [], should_continue: true }), // quality 5
100
+ ];
101
+ const result = await run({
102
+ task: "Test max rounds",
103
+ execute: mockExecutor(responses),
104
+ maxRounds: 3,
105
+ });
106
+ assert.equal(result.stopReason, "max_rounds");
107
+ assert.equal(result.roundsCompleted, 3);
108
+ });
109
+ it("stops on executor_failure after consecutive errors", async () => {
110
+ let calls = 0;
111
+ const result = await run({
112
+ task: "Test executor failure",
113
+ execute: async () => {
114
+ calls++;
115
+ throw new Error("API key expired");
116
+ },
117
+ maxRounds: 10,
118
+ maxConsecutiveErrors: 3,
119
+ });
120
+ assert.equal(result.stopReason, "executor_failure");
121
+ assert.equal(calls, 3);
122
+ });
123
+ it("recovers from a single execute error", async () => {
124
+ let calls = 0;
125
+ const result = await run({
126
+ task: "Test recover from error",
127
+ execute: async () => {
128
+ calls++;
129
+ if (calls === 1)
130
+ throw new Error("transient error");
131
+ return makeAgentOutput({ should_continue: false });
132
+ },
133
+ maxRounds: 10,
134
+ });
135
+ // Should succeed — only 1 error, not 3 consecutive
136
+ assert.equal(result.stopReason, "task_complete");
137
+ assert.equal(calls, 2);
138
+ });
139
+ });
140
+ // ═══════════════════════════════════════════════════════════════════════════
141
+ // LoopRuntime class
142
+ // ═══════════════════════════════════════════════════════════════════════════
143
+ describe("LoopRuntime", () => {
144
+ it("status transitions: IDLE → RUNNING → STOPPED", async () => {
145
+ const rt = new LoopRuntime({
146
+ task: "Test status transitions",
147
+ execute: mockExecutor([
148
+ makeAgentOutput({ should_continue: false }),
149
+ ]),
150
+ });
151
+ assert.equal(rt.status, "idle");
152
+ const result = await rt.start();
153
+ assert.equal(result.stopReason, "task_complete");
154
+ // After start() resolves, runtime is stopped
155
+ const finalStatus = rt.status;
156
+ assert.notEqual(finalStatus, RuntimeStatus.RUNNING);
157
+ assert.notEqual(finalStatus, RuntimeStatus.IDLE);
158
+ });
159
+ it("stop() mid-loop stops gracefully", async () => {
160
+ const rt = new LoopRuntime({
161
+ task: "Test stop mid-loop",
162
+ execute: mockExecutor([
163
+ makeAgentOutput({ should_continue: true }),
164
+ makeAgentOutput({ should_continue: true }),
165
+ makeAgentOutput({ should_continue: true }),
166
+ ]),
167
+ maxRounds: 10,
168
+ onRoundComplete: (info) => {
169
+ if (info.round === 2) {
170
+ rt.stop();
171
+ }
172
+ },
173
+ });
174
+ const result = await rt.start();
175
+ assert.equal(result.stopReason, "stopped");
176
+ // stop() is called in round 2's onRoundComplete; the for-loop
177
+ // increments to round 3 before checking status, so roundsCompleted
178
+ // reflects the incremented counter
179
+ assert.ok(result.roundsCompleted <= 3);
180
+ });
181
+ it("getCurrentRound and getQualityTrajectory work", async () => {
182
+ const rt = new LoopRuntime({
183
+ task: "Test accessors",
184
+ execute: mockExecutor([
185
+ makeAgentOutput({ should_continue: true }),
186
+ makeAgentOutput({ should_continue: false }),
187
+ ]),
188
+ maxRounds: 10,
189
+ });
190
+ assert.equal(rt.getCurrentRound(), 1); // before start
191
+ assert.equal(rt.getQualityTrajectory().length, 0);
192
+ await rt.start();
193
+ assert.equal(rt.getQualityTrajectory().length, 2);
194
+ });
195
+ });
196
+ // ═══════════════════════════════════════════════════════════════════════════
197
+ // Heartbeat & timeout
198
+ // ═══════════════════════════════════════════════════════════════════════════
199
+ describe("Heartbeat & timeout", () => {
200
+ it("heartbeat events fire during slow execute", async () => {
201
+ const heartbeats = [];
202
+ const result = await run({
203
+ task: "Test heartbeat",
204
+ execute: slowExecutor([makeAgentOutput({ should_continue: false })], 150),
205
+ heartbeatIntervalMs: 50,
206
+ roundTimeoutMs: 5000,
207
+ maxRounds: 10,
208
+ onHeartbeat: (info) => {
209
+ heartbeats.push(info);
210
+ },
211
+ });
212
+ assert.equal(result.stopReason, "task_complete");
213
+ // Should have received at least one heartbeat during the 150ms delay
214
+ assert.ok(heartbeats.length >= 1, `expected >=1 heartbeats, got ${heartbeats.length}`);
215
+ });
216
+ it("timeout sets signal.aborted", async () => {
217
+ let signalWasAborted = false;
218
+ const result = await run({
219
+ task: "Test timeout",
220
+ execute: async (_prompt, ctx) => {
221
+ // Sleep past the timeout
222
+ await new Promise((r) => setTimeout(r, 200));
223
+ if (ctx && ctx.signal.aborted) {
224
+ signalWasAborted = true;
225
+ }
226
+ return makeAgentOutput({ should_continue: false });
227
+ },
228
+ roundTimeoutMs: 50,
229
+ heartbeatIntervalMs: 25,
230
+ stallGraceMs: 5000,
231
+ maxRounds: 10,
232
+ });
233
+ assert.equal(result.stopReason, "task_complete");
234
+ assert.ok(signalWasAborted, "signal.aborted should be true after timeout");
235
+ });
236
+ it("interactive mode does not trigger timeout", async () => {
237
+ let timeoutFired = false;
238
+ const result = await run({
239
+ task: "Test interactive",
240
+ execute: async (_prompt, _ctx) => {
241
+ await new Promise((r) => setTimeout(r, 150));
242
+ return makeAgentOutput({ should_continue: false });
243
+ },
244
+ interactive: true,
245
+ roundTimeoutMs: 50,
246
+ heartbeatIntervalMs: 25,
247
+ maxRounds: 10,
248
+ onTimeout: () => {
249
+ timeoutFired = true;
250
+ },
251
+ });
252
+ assert.equal(result.stopReason, "task_complete");
253
+ assert.equal(timeoutFired, false);
254
+ });
255
+ it("reportProgress resets stall timer", async () => {
256
+ let reported = false;
257
+ const result = await run({
258
+ task: "Test reportProgress",
259
+ execute: async (_prompt, ctx) => {
260
+ ctx?.reportProgress("still working...");
261
+ reported = true;
262
+ await new Promise((r) => setTimeout(r, 50));
263
+ return makeAgentOutput({ should_continue: false });
264
+ },
265
+ roundTimeoutMs: 5000,
266
+ heartbeatIntervalMs: 20,
267
+ maxRounds: 10,
268
+ });
269
+ assert.equal(result.stopReason, "task_complete");
270
+ assert.ok(reported);
271
+ });
272
+ });
273
+ // ═══════════════════════════════════════════════════════════════════════════
274
+ // Circuit breaker & extraction failure
275
+ // ═══════════════════════════════════════════════════════════════════════════
276
+ describe("Circuit breaker & extraction", () => {
277
+ it("circuit breaker triggers after consecutive low quality", async () => {
278
+ // Generate failing outputs for 5+ rounds to trigger circuit breaker
279
+ const responses = Array.from({ length: 10 }, () => makeFailingOutput(["violated constraint X"]));
280
+ const result = await run({
281
+ task: "Test circuit breaker",
282
+ execute: mockExecutor(responses),
283
+ maxRounds: 10,
284
+ });
285
+ // Either circuit_breaker or max_rounds — depends on policy
286
+ assert.ok(result.stopReason === "circuit_breaker" ||
287
+ result.stopReason === "max_rounds", `expected circuit_breaker or max_rounds, got ${result.stopReason}`);
288
+ });
289
+ it("stops on extraction failure (no eval block)", async () => {
290
+ const result = await run({
291
+ task: "Test extraction failure",
292
+ execute: mockExecutor([
293
+ makeAgentOutput({ should_continue: true }),
294
+ "No structured eval block here, still need to continue working on more tasks.", // heuristic will detect "remaining" → should_continue=true, but extraction is heuristic → stalled
295
+ ]),
296
+ maxRounds: 10,
297
+ });
298
+ // Extraction via heuristic → extractionSucceeded=false → stalled
299
+ assert.equal(result.stopReason, "stalled");
300
+ });
301
+ });
302
+ // ═══════════════════════════════════════════════════════════════════════════
303
+ // Stall detection
304
+ // ═══════════════════════════════════════════════════════════════════════════
305
+ describe("Stall detection", () => {
306
+ it("stalls when execute exceeds timeout + stall grace", async () => {
307
+ const result = await run({
308
+ task: "Test stall",
309
+ execute: async (_prompt, _ctx) => {
310
+ // Sleep past timeout + stall grace
311
+ await new Promise((r) => setTimeout(r, 300));
312
+ return makeAgentOutput({ should_continue: false });
313
+ },
314
+ roundTimeoutMs: 50,
315
+ heartbeatIntervalMs: 25,
316
+ stallGraceMs: 50,
317
+ maxRounds: 10,
318
+ });
319
+ // Should be stalled (status was set to STALLED but execute returned)
320
+ assert.ok(["stalled", "task_complete"].includes(result.stopReason), `expected stalled or task_complete, got ${result.stopReason}`);
321
+ });
322
+ });
323
+ //# sourceMappingURL=runtime.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.test.js","sourceRoot":"","sources":["../../src/tests/runtime.test.ts"],"names":[],"mappings":"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"}
package/loop_policy.json CHANGED
@@ -37,6 +37,13 @@
37
37
  "feedback_flush_interval": 5,
38
38
  "max_circuit_breaker": 3
39
39
  },
40
+ "runtime": {
41
+ "max_rounds": 20,
42
+ "round_timeout_ms": 600000,
43
+ "heartbeat_interval_ms": 30000,
44
+ "stall_grace_ms": 300000,
45
+ "max_consecutive_errors": 3
46
+ },
40
47
  "backend": {
41
48
  "vault_path": ".promptcraft/prompt_vault.json",
42
49
  "global_vault_path": "~/.promptcraft/global_vault.json"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopforge",
3
- "version": "1.1.1",
3
+ "version": "1.3.0",
4
4
  "description": "Loop-Time Intelligence Layer for AI coding agents — per-iteration prompt compiler with structured memory, constraint inheritance, and drift correction.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,23 +18,25 @@
18
18
  "import": "./dist/replay.js",
19
19
  "types": "./dist/replay.d.ts"
20
20
  },
21
- "./autonomous": {
22
- "import": "./dist/autonomous.js",
23
- "types": "./dist/autonomous.d.ts"
21
+ "./mcp": {
22
+ "import": "./dist/mcp/server.js",
23
+ "types": "./dist/mcp/server.d.ts"
24
24
  }
25
25
  },
26
26
  "bin": {
27
- "loopforge": "./dist/cli.js"
27
+ "loopforge": "./dist/cli.js",
28
+ "loopforge-mcp": "./dist/mcp-server.js"
28
29
  },
29
30
  "files": [
30
31
  "dist",
32
+ "skills",
31
33
  "loop_policy.json",
32
34
  "LICENSE"
33
35
  ],
34
36
  "scripts": {
35
37
  "build": "tsc && node dist/generate-schema.js",
36
38
  "generate-schema": "tsc && node dist/generate-schema.js",
37
- "test": "tsc && node dist/generate-schema.js && node --test dist/tests/*.test.js",
39
+ "test": "tsc && node dist/generate-schema.js && node --test dist/tests/*.test.js && node -e \"require('fs').rmSync('.promptcraft',{recursive:true,force:true})\"",
38
40
  "test:watch": "tsc && node --test --watch dist/tests/*.test.js",
39
41
  "check": "tsc --noEmit"
40
42
  },
@@ -0,0 +1,186 @@
1
+ ---
2
+ name: perception
3
+ description: Multi-round autonomous loop driver powered by LoopForge MCP. Compiles context-aware prompts per iteration, tracks quality, inherits constraints, and stops when work is done — not when rounds run out.
4
+ ---
5
+
6
+ # Perception — Loop-Time Intelligence Skill
7
+
8
+ **Perception** turns any AI agent into a self-aware multi-round executor. It
9
+ drives the LoopForge MCP server (`loopforge-mcp`) to compile per-iteration
10
+ prompts from running quality trajectory, constraint inheritance, and drift
11
+ detection — maintaining cognitive stability across long-horizon loops.
12
+
13
+ Works with Claude Code, Codex, and any MCP-capable host. Zero configuration
14
+ beyond having `loopforge-mcp` registered as an MCP server.
15
+
16
+ ## When to Activate
17
+
18
+ Activate when the user says any of:
19
+ - `/loop <task>` — start an autonomous multi-round loop
20
+ - "do this in a loop", "keep going until done", "iterate on this"
21
+ - Any task that clearly needs 3+ rounds (audit, refactor, migrate, review-and-fix cycles)
22
+
23
+ Also activate implicitly when the user's request is too large for a single
24
+ round (e.g. "audit the entire codebase and fix every issue").
25
+
26
+ ## Core Workflow
27
+
28
+ ```
29
+ ┌─────────────────────────────────────────────────────┐
30
+ │ 1. loopforge_start(task, constraints, maxRounds) │
31
+ │ → sessionId + Round 1 prompt │
32
+ │ │
33
+ │ 2. Execute the prompt (read, write, test, fix) │
34
+ │ MUST include ---loopforge-eval block in output │
35
+ │ │
36
+ │ 3. loopforge_next(sessionId, output) │
37
+ │ → if prompt: go to step 2 │
38
+ │ → if prompt=null: loop ended, read stopReason │
39
+ └─────────────────────────────────────────────────────┘
40
+ ```
41
+
42
+ ### Step-by-step
43
+
44
+ **Step 1 — Start the loop:**
45
+ ```
46
+ Call loopforge_start with:
47
+ task: required — the full task description
48
+ maxRounds: optional — default 20 from policy
49
+ constraints: optional — hard constraints as string[]
50
+ domain: optional — domain hint (solidity, react, rust…)
51
+
52
+ Keep the returned sessionId — you will need it for every subsequent call.
53
+ ```
54
+
55
+ **Step 2 — Execute the round:**
56
+ Execute the compiled prompt exactly as you would any user task. Read files,
57
+ write code, run tests, fix bugs. The prompt already contains the task scope,
58
+ constraints, and quality expectations for this specific round.
59
+
60
+ **CRITICAL: Every round's output MUST end with a self-evaluation block:**
61
+ ```
62
+ ---loopforge-eval
63
+ {
64
+ "success": true,
65
+ "output_summary": "Fixed 3 reentrancy bugs in withdraw() and deposit(). All 12 tests pass.",
66
+ "constraint_violations": [],
67
+ "should_continue": true
68
+ }
69
+ ---end-loopforge-eval
70
+ ```
71
+
72
+ **Field rules:**
73
+
74
+ | Field | Type | Rule |
75
+ |-------|------|------|
76
+ | `success` | boolean | `true` ONLY if all hard constraints met AND the task goal achieved |
77
+ | `output_summary` | string | Specific, actionable. What was DONE this round — not what was attempted |
78
+ | `constraint_violations` | string[] | Constraints the agent actually violated this round. Be honest — hiding violations corrupts the quality signal and defeats the circuit breaker |
79
+ | `should_continue` | boolean | `false` ONLY when the ENTIRE task is complete. Partial progress = `true` |
80
+
81
+ **Why this matters:** Without a valid `---loopforge-eval` block, extraction
82
+ fails and the loop stops with `stopReason: stalled`. The circuit breaker
83
+ uses `success` + `violations` to compute quality scores — lying here defeats
84
+ the only mechanism that prevents infinite loops.
85
+
86
+ **Step 3 — Advance to next round:**
87
+ ```
88
+ Call loopforge_next with:
89
+ sessionId: from loopforge_start
90
+ output: your FULL output from this round (including the eval block)
91
+ ```
92
+
93
+ If the result has `prompt: null`, the loop has ended. Read `stopReason`:
94
+ - `task_complete` — you reported should_continue=false. Work is done.
95
+ - `circuit_breaker` — quality flat or declining for 3+ rounds. Review your approach.
96
+ - `max_rounds` — hit the round limit. Decide whether to extend or accept.
97
+ - `stalled` — no valid self-eval block found. Check your output format.
98
+
99
+ If the result has a non-null `prompt`, execute it and repeat from Step 2.
100
+
101
+ ## Tool Reference
102
+
103
+ | Tool | When to call | Key input | Key output |
104
+ |------|-------------|-----------|------------|
105
+ | `loopforge_start` | Beginning of every loop | `task`, `maxRounds?`, `constraints?` | `sessionId`, round 1 `prompt` |
106
+ | `loopforge_next` | After executing every round | `sessionId`, `output` (with eval block) | next `prompt` or `null` + `stopReason` |
107
+ | `loopforge_status` | Mid-loop checkpoint, user asks "how's it going" | `sessionId` | `round`, `qualityTrajectory`, `status` |
108
+ | `loopforge_stop` | User wants to abort, fatal error | `sessionId` | `roundsCompleted`, final trajectory |
109
+ | `loopforge_list` | User asks "what loops are running" | — | `sessions[]` |
110
+ | `loopforge_replay` | After loop ends, user asks "show me what happened" | `sessionId` | `timeline[]` with all rounds |
111
+
112
+ ## Quality Signals (Read the Room)
113
+
114
+ The prompt changes between rounds based on your trajectory. Pay attention to:
115
+
116
+ - **Compile level** — `l0` (cached, fast path), `l1` (patched, mild drift),
117
+ `l2` (full recompile, significant change). L2 means the compiler detected a
118
+ major shift — read the prompt carefully.
119
+ - **Warnings** — constraint violations accumulating, task drift, quality
120
+ decline. These are the compiler begging you to course-correct.
121
+ - **Technique rotation** — the compiler may switch from `zero-shot-cot` to
122
+ `tree-of-thought` if quality drops. Follow the new technique.
123
+
124
+ ## Stop Condition Matrix
125
+
126
+ | Condition | stopReason | What to do |
127
+ |-----------|-----------|------------|
128
+ | You set `should_continue: false` | `task_complete` | Report final results to user |
129
+ | 3+ rounds of flat/declining quality | `circuit_breaker` | Tell user the approach is stuck, suggest a different strategy |
130
+ | Round count reached `maxRounds` | `max_rounds` | Summarize progress, ask user whether to extend |
131
+ | No `---loopforge-eval` block found | `stalled` | Fix your output format and restart |
132
+ | User interrupts or fatal error | (call `loopforge_stop`) | Clean stop with trajectory preserved |
133
+
134
+ ## Rules
135
+
136
+ 1. **Never skip the eval block.** No exceptions. If you forget, the loop stalls.
137
+ 2. **Be honest in self-evaluation.** Lying about success or hiding violations
138
+ produces a false quality signal. The circuit breaker exists to stop bad
139
+ loops — if you fake quality=5 every round, it fires anyway.
140
+ 3. **One loop per task.** Don't reuse a sessionId across different tasks.
141
+ 4. **Execute the prompt you're given.** The compiler may change technique or
142
+ narrow scope between rounds. Trust it — it sees the trajectory.
143
+ 5. **Call loopforge_next within the same turn.** Don't leave a round hanging
144
+ across conversation turns. The MCP server is in-memory.
145
+
146
+ ## Example
147
+
148
+ ```
149
+ User: /loop "Audit the ERC20 token in contracts/Token.sol for security issues"
150
+
151
+ Agent:
152
+ → loopforge_start({ task: "Audit ERC20 token in contracts/Token.sol for security issues",
153
+ domain: "solidity",
154
+ constraints: ["must not break existing tests", "follow check-effects-interactions"] })
155
+ ← { sessionId: "abc-123", round: 1, prompt: "## LoopForge Loop Compile — Round 1\n...", level: "l2" }
156
+
157
+ [Executes prompt: reads Token.sol, identifies 4 issues, writes audit notes]
158
+
159
+ Output ends with:
160
+ ---loopforge-eval
161
+ {"success":false,"output_summary":"Found 4 potential issues: 2 reentrancy, 1 overflow, 1 access control. Not yet fixed.","constraint_violations":[],"should_continue":true}
162
+ ---end-loopforge-eval
163
+
164
+ → loopforge_next({ sessionId: "abc-123", output: <full output> })
165
+ ← { sessionId: "abc-123", round: 2, prompt: "## LoopForge Loop Compile — Round 2\n...", level: "l1" }
166
+
167
+ [Executes prompt: fixes 3 issues, 1 needs more investigation]
168
+
169
+ ---loopforge-eval
170
+ {"success":false,"output_summary":"Fixed reentrancy in withdraw() and overflow in calcReward(). Access control issue in setOwner() needs design discussion.","constraint_violations":[],"should_continue":true}
171
+ ---end-loopforge-eval
172
+
173
+ → loopforge_next({ sessionId: "abc-123", output: <full output> })
174
+ ← { sessionId: "abc-123", round: 3, prompt: "## LoopForge Loop Compile — Round 3\n...", level: "l0" }
175
+
176
+ [Executes prompt: documents access control issue for user decision, all fixes pass tests]
177
+
178
+ ---loopforge-eval
179
+ {"success":true,"output_summary":"All fixable issues resolved. 1 access control design question flagged for user. 24/24 tests pass.","constraint_violations":[],"should_continue":false}
180
+ ---end-loopforge-eval
181
+
182
+ → loopforge_next({ sessionId: "abc-123", output: <full output> })
183
+ ← { sessionId: "abc-123", round: 3, prompt: null, stopReason: "task_complete", quality: 5 }
184
+
185
+ Reports to user: "Audit complete in 3 rounds. 3 issues fixed, 1 design question flagged."
186
+ ```
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: prompt-techniques
3
+ description: >
4
+ Reference catalog of 7 prompt engineering techniques. This skill should be
5
+ used when the AI needs to recall the purpose, method steps, and use cases
6
+ of techniques like zero-shot, few-shot, chain-of-thought, step-back,
7
+ least-to-most, or tree-of-thought. It is a pure reference skill — no
8
+ workflow instructions, only technique documentation loaded on demand.
9
+ ---
10
+
11
+ # Prompt Techniques Reference
12
+
13
+ This skill catalogs seven prompt engineering techniques. Use `references/` files
14
+ to load detailed technique documentation on demand. Each reference includes:
15
+ purpose, input requirements, recommended JSON input templates, method steps,
16
+ design rules, when-to-use guidance, and example use cases.
17
+
18
+ ## Technique Overview
19
+
20
+ | Technique | Cognitive Load | Independence | When to Use |
21
+ |-----------|---------------|-------------|-------------|
22
+ | zero-shot | Low | Either | Simple code explanation, formatting, renaming. |
23
+ | few-shot | Medium | Continuous | Standard CRUD modules, unit tests with fixed patterns. |
24
+ | chain-of-thought | Medium-High | Either | Multi-step reasoning; use `zero-shot-cot` without examples, `few-shot-cot` with examples. |
25
+ | step-back | High | Independent | Vague errors, messy legacy refactoring — abstract principles first. |
26
+ | least-to-most | High | Continuous | Large multi-step modules — decompose into ordered sub-tasks. |
27
+ | tree-of-thought | High | Independent | Core algorithms, crypto/signature verification, Assembly ops — explore multiple candidate paths. |
28
+
29
+ ## How to Use
30
+
31
+ 1. Read `references/<technique>.md` for the selected technique. Each reference contains:
32
+ - **Purpose** — what problem the technique solves.
33
+ - **Input Requirements** — required and optional parameters.
34
+ - **Recommended JSON Input** — a complete input template with example values.
35
+ - **Method Steps** — step-by-step construction guide.
36
+ - **Design Rules** — specific rules for high-quality prompt construction.
37
+ - **Case Generation Rules** — how to generate examples, decompositions, branches, or abstractions (where applicable).
38
+ - **Single-Pass vs Two-Stage** — when to use each execution mode (step-back, least-to-most).
39
+ - **Search Strategy Selection** — beam/dfs/expert-panel guidance (tree-of-thought).
40
+ - **Prompt Output Template** — a complete 8-section output skeleton with section-level format specifications. Defines the exact structure the generated prompt must follow. The technique-specific section (section 5) format varies per technique: Few-Shot uses input→output pairs, Few-Shot-CoT uses reasoning triples, Step-Back uses abstraction framework boxes, Least-to-Most uses ordered subproblems, Tree-of-Thought uses state tables + evaluation criteria. Zero-Shot omits section 5 entirely for a lightweight 7-section prompt.
41
+ - **When to Use** — concrete scenarios and example use cases.
42
+ 2. `references/chain-of-thought.md` covers both `zero-shot-cot` and `few-shot-cot`, including paper citations for Few-Shot-CoT.
43
+ 3. Do not load all references at once — read only the one selected by the router in Step 1.
44
+
45
+ ## Reference Files
46
+
47
+ - `references/zero-shot.md`
48
+ - `references/few-shot.md`
49
+ - `references/chain-of-thought.md` (covers zero-shot-cot and few-shot-cot)
50
+ - `references/step-back.md`
51
+ - `references/least-to-most.md`
52
+ - `references/tree-of-thought.md`