loopforge 1.3.1 → 1.8.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 (91) hide show
  1. package/README.md +64 -3
  2. package/dist/backends/fs.d.ts +5 -0
  3. package/dist/backends/fs.d.ts.map +1 -1
  4. package/dist/backends/fs.js +66 -16
  5. package/dist/backends/fs.js.map +1 -1
  6. package/dist/builder.d.ts +0 -1
  7. package/dist/builder.d.ts.map +1 -1
  8. package/dist/builder.js +14 -25
  9. package/dist/builder.js.map +1 -1
  10. package/dist/engine.d.ts +28 -5
  11. package/dist/engine.d.ts.map +1 -1
  12. package/dist/engine.js +303 -105
  13. package/dist/engine.js.map +1 -1
  14. package/dist/index.d.ts +9 -12
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +7 -10
  17. package/dist/index.js.map +1 -1
  18. package/dist/loop-compiler.d.ts +28 -2
  19. package/dist/loop-compiler.d.ts.map +1 -1
  20. package/dist/loop-compiler.js +718 -38
  21. package/dist/loop-compiler.js.map +1 -1
  22. package/dist/mcp/server.d.ts.map +1 -1
  23. package/dist/mcp/server.js +6 -4
  24. package/dist/mcp/server.js.map +1 -1
  25. package/dist/mcp/session.d.ts +24 -4
  26. package/dist/mcp/session.d.ts.map +1 -1
  27. package/dist/mcp/session.js +303 -34
  28. package/dist/mcp/session.js.map +1 -1
  29. package/dist/mcp/tools.d.ts +165 -1
  30. package/dist/mcp/tools.d.ts.map +1 -1
  31. package/dist/mcp/tools.js +144 -15
  32. package/dist/mcp/tools.js.map +1 -1
  33. package/dist/memory-bridge.d.ts +47 -0
  34. package/dist/memory-bridge.d.ts.map +1 -0
  35. package/dist/memory-bridge.js +290 -0
  36. package/dist/memory-bridge.js.map +1 -0
  37. package/dist/observability.d.ts +23 -0
  38. package/dist/observability.d.ts.map +1 -0
  39. package/dist/observability.js +29 -0
  40. package/dist/observability.js.map +1 -0
  41. package/dist/policy.d.ts +72 -0
  42. package/dist/policy.d.ts.map +1 -1
  43. package/dist/policy.js +44 -0
  44. package/dist/policy.js.map +1 -1
  45. package/dist/protocol.d.ts +197 -7
  46. package/dist/protocol.d.ts.map +1 -1
  47. package/dist/protocol.js +48 -5
  48. package/dist/protocol.js.map +1 -1
  49. package/dist/runtime.d.ts +19 -0
  50. package/dist/runtime.d.ts.map +1 -1
  51. package/dist/runtime.js +446 -142
  52. package/dist/runtime.js.map +1 -1
  53. package/dist/tests/builder.test.js +1 -25
  54. package/dist/tests/builder.test.js.map +1 -1
  55. package/dist/tests/engine.test.js +213 -38
  56. package/dist/tests/engine.test.js.map +1 -1
  57. package/dist/tests/generate-schema.test.js +4 -4
  58. package/dist/tests/generate-schema.test.js.map +1 -1
  59. package/dist/tests/loop-compiler.test.js +427 -2
  60. package/dist/tests/loop-compiler.test.js.map +1 -1
  61. package/dist/tests/mcp.test.js +166 -79
  62. package/dist/tests/mcp.test.js.map +1 -1
  63. package/dist/tests/memory-bridge.test.d.ts +8 -0
  64. package/dist/tests/memory-bridge.test.d.ts.map +1 -0
  65. package/dist/tests/memory-bridge.test.js +384 -0
  66. package/dist/tests/memory-bridge.test.js.map +1 -0
  67. package/dist/tests/protocol.test.js +14 -5
  68. package/dist/tests/protocol.test.js.map +1 -1
  69. package/dist/tests/verification-gate.test.d.ts +2 -0
  70. package/dist/tests/verification-gate.test.d.ts.map +1 -0
  71. package/dist/tests/verification-gate.test.js +407 -0
  72. package/dist/tests/verification-gate.test.js.map +1 -0
  73. package/dist/verification-gate.d.ts +26 -0
  74. package/dist/verification-gate.d.ts.map +1 -0
  75. package/dist/verification-gate.js +232 -0
  76. package/dist/verification-gate.js.map +1 -0
  77. package/loop_policy.json +31 -0
  78. package/package.json +1 -2
  79. package/skills/perception/SKILL.md +147 -55
  80. package/dist/adapter.d.ts +0 -17
  81. package/dist/adapter.d.ts.map +0 -1
  82. package/dist/adapter.js +0 -228
  83. package/dist/adapter.js.map +0 -1
  84. package/dist/cli.d.ts +0 -7
  85. package/dist/cli.d.ts.map +0 -1
  86. package/dist/cli.js +0 -458
  87. package/dist/cli.js.map +0 -1
  88. package/dist/tests/adapter.test.d.ts +0 -2
  89. package/dist/tests/adapter.test.d.ts.map +0 -1
  90. package/dist/tests/adapter.test.js +0 -104
  91. package/dist/tests/adapter.test.js.map +0 -1
@@ -0,0 +1,232 @@
1
+ /** Verification Gate — Layer 1 cross-round consistency checks.
2
+ *
3
+ * Pure-function module. Validates an agent's SelfEvaluation against the
4
+ * loop's own lineage before it enters the compiler.
5
+ *
6
+ * Verdict semantics:
7
+ * - trusted: all checks passed; flags are informational only.
8
+ * - suspect: one or more warn-level flags; flags become warnings in
9
+ * the next prompt so the agent can clarify.
10
+ * - contradicted: one or more error-level flags; the quality score for
11
+ * this round is excluded from the quality trend (NOT
12
+ * modified). Flags become hard constraints — the agent
13
+ * must respond in the next round.
14
+ */
15
+ import { makeVerificationFlag, makeVerificationResult } from "./protocol.js";
16
+ // ═══════════════════════════════════════════════════════════════════════════
17
+ // Helpers
18
+ // ═══════════════════════════════════════════════════════════════════════════
19
+ /** Extract the round number from a vault entry's loop_lineage.
20
+ * Returns 0 if the entry has no lineage or no round field.
21
+ * In practice, persistLoopLineage always writes round ≥ 1, so 0
22
+ * unambiguously means "not a valid round entry" in this context. */
23
+ function entryRound(entry) {
24
+ const lineage = (entry.loop_lineage ?? {});
25
+ return lineage.round ?? 0;
26
+ }
27
+ /** Read constraint_violations from a vault entry (entry-level, stored from
28
+ * the previous round's last_round_result at persist time). */
29
+ function entryViolations(entry) {
30
+ const viols = entry.constraint_violations;
31
+ if (Array.isArray(viols))
32
+ return viols.filter((v) => typeof v === "string");
33
+ return [];
34
+ }
35
+ // ═══════════════════════════════════════════════════════════════════════════
36
+ // Individual checks — each returns a VerificationFlag or null
37
+ // ═══════════════════════════════════════════════════════════════════════════
38
+ function checkProgressRegression(selfEval, prevSelfEval) {
39
+ if (!prevSelfEval?.execution_evidence)
40
+ return null;
41
+ if (!selfEval.execution_evidence)
42
+ return null;
43
+ const prevProgress = prevSelfEval.execution_evidence.progress_estimate;
44
+ const currProgress = selfEval.execution_evidence.progress_estimate;
45
+ if (typeof prevProgress !== "number" || typeof currProgress !== "number")
46
+ return null;
47
+ // Use delta with epsilon to avoid IEEE 754 rounding issues (0.8 - 0.2 > 0.6 in float)
48
+ if (prevProgress - currProgress <= 0.2 + 1e-10)
49
+ return null;
50
+ return makeVerificationFlag({
51
+ severity: "warn",
52
+ field: "progress_estimate",
53
+ check: "progress_regression",
54
+ detail: `Progress dropped from ${prevProgress.toFixed(2)} to ` +
55
+ `${currProgress.toFixed(2)} (delta: ${(currProgress - prevProgress).toFixed(2)})`,
56
+ });
57
+ }
58
+ function checkEmptyChangeWithPassing(selfEval) {
59
+ const ev = selfEval.execution_evidence;
60
+ if (!ev)
61
+ return null;
62
+ const filesEmpty = ev.files_changed.length === 0;
63
+ const testsAllPass = ev.test_results !== null &&
64
+ ev.test_results.failed === 0 &&
65
+ ev.test_results.passed > 0;
66
+ if (!filesEmpty || !testsAllPass || !selfEval.success)
67
+ return null;
68
+ return makeVerificationFlag({
69
+ severity: "warn",
70
+ field: "execution_evidence",
71
+ check: "empty_change_with_passing",
72
+ detail: "Agent claims success with no files changed and all tests passing — " +
73
+ "verify that work was actually performed",
74
+ });
75
+ }
76
+ function checkSuccessWithRemainingCriteria(selfEval) {
77
+ if (!selfEval.success)
78
+ return null;
79
+ const remaining = selfEval.execution_evidence?.success_criteria_remaining;
80
+ if (!remaining || remaining.length === 0)
81
+ return null;
82
+ return makeVerificationFlag({
83
+ severity: "error",
84
+ field: "success",
85
+ check: "success_with_remaining_criteria",
86
+ detail: `Agent claims success but ${remaining.length} criteria remain unmet: ` +
87
+ remaining.slice(0, 3).join("; "),
88
+ });
89
+ }
90
+ function checkDuplicateConstraintDiscovery(selfEval, prevSelfEval, olderViolations) {
91
+ const discovered = selfEval.discovered_constraints;
92
+ if (!discovered || discovered.length === 0)
93
+ return null;
94
+ // Collect all previously-known constraints
95
+ const known = new Set();
96
+ for (const v of olderViolations)
97
+ known.add(v.toLowerCase().trim());
98
+ if (prevSelfEval) {
99
+ for (const d of prevSelfEval.discovered_constraints ?? []) {
100
+ known.add(d.toLowerCase().trim());
101
+ }
102
+ // Also treat previous violations as implicitly discovered
103
+ for (const v of prevSelfEval.constraint_violations) {
104
+ known.add(v.toLowerCase().trim());
105
+ }
106
+ }
107
+ for (const d of discovered) {
108
+ if (known.has(d.toLowerCase().trim())) {
109
+ return makeVerificationFlag({
110
+ severity: "warn",
111
+ field: "discovered_constraints",
112
+ check: "duplicate_constraint_discovery",
113
+ detail: `Constraint "${d}" was already known from a previous round`,
114
+ });
115
+ }
116
+ }
117
+ return null;
118
+ }
119
+ function checkRecurringViolation(selfEval, prevSelfEval, vaultEntries, currentRound) {
120
+ const currViols = selfEval.constraint_violations;
121
+ if (!currViols || currViols.length === 0)
122
+ return null;
123
+ // Build the violation history: [round N-2, round N-1, round N]
124
+ const violationsByRound = [];
125
+ // Round N-2 violations come from the vault entry for round N-1
126
+ // (persistLoopLineage stores the PREVIOUS round's violations on each entry)
127
+ if (currentRound >= 3) {
128
+ const entryNMinus1 = vaultEntries.find((e) => entryRound(e) === currentRound - 1);
129
+ if (entryNMinus1) {
130
+ const viols = entryViolations(entryNMinus1);
131
+ if (viols.length)
132
+ violationsByRound.push(viols.map((v) => v.toLowerCase().trim()));
133
+ }
134
+ }
135
+ // Round N-1 violations from prevSelfEval
136
+ if (prevSelfEval) {
137
+ const prevViols = prevSelfEval.constraint_violations;
138
+ violationsByRound.push(prevViols.map((v) => v.toLowerCase().trim()));
139
+ }
140
+ // Round N violations from current selfEval
141
+ violationsByRound.push(currViols.map((v) => v.toLowerCase().trim()));
142
+ // Need at least 3 rounds of data
143
+ if (violationsByRound.length < 3)
144
+ return null;
145
+ // Check each current violation against the previous 2 rounds
146
+ const [rNMinus2, rNMinus1, rN] = violationsByRound.slice(-3);
147
+ for (const v of rN) {
148
+ if (rNMinus1.includes(v) && rNMinus2.includes(v)) {
149
+ return makeVerificationFlag({
150
+ severity: "error",
151
+ field: "constraint_violations",
152
+ check: "recurring_violation",
153
+ detail: `Constraint violation "${v}" has appeared in 3 consecutive rounds ` +
154
+ `(rounds ${currentRound - 2}–${currentRound}) without resolution`,
155
+ });
156
+ }
157
+ }
158
+ return null;
159
+ }
160
+ function checkRetractFreshConstraint(selfEval, prevSelfEval, currentRound) {
161
+ const retracted = selfEval.retracted_constraints;
162
+ if (!retracted || retracted.length === 0)
163
+ return null;
164
+ if (!prevSelfEval)
165
+ return null;
166
+ const lastRoundDiscoveries = new Set();
167
+ for (const d of prevSelfEval.discovered_constraints ?? []) {
168
+ lastRoundDiscoveries.add(d.toLowerCase().trim());
169
+ }
170
+ for (const r of retracted) {
171
+ if (lastRoundDiscoveries.has(r.toLowerCase().trim())) {
172
+ return makeVerificationFlag({
173
+ severity: "warn",
174
+ field: "retracted_constraints",
175
+ check: "retract_fresh_constraint",
176
+ detail: `Retracting constraint "${r}" that was just discovered in round ` +
177
+ `${currentRound - 1} — may indicate rapid flip-flopping`,
178
+ });
179
+ }
180
+ }
181
+ return null;
182
+ }
183
+ // ═══════════════════════════════════════════════════════════════════════════
184
+ // Main entry point
185
+ // ═══════════════════════════════════════════════════════════════════════════
186
+ /** Verify a SelfEvaluation against the loop's cross-round lineage.
187
+ *
188
+ * @param selfEval The agent's self-evaluation for the current round.
189
+ * @param currentRound The current round number (1-based).
190
+ * @param vaultEntries Vault entries for this loop (non-feedback only).
191
+ * @param prevSelfEval The agent's self-evaluation from the previous round
192
+ * (null for round 1).
193
+ */
194
+ export function verifySelfEvaluation(selfEval, currentRound, vaultEntries, prevSelfEval = null) {
195
+ const flags = [];
196
+ // Collect violations from all previous vault entries for duplicate-discovery
197
+ // and other checks that need deeper history.
198
+ const olderViolations = [];
199
+ for (const entry of vaultEntries) {
200
+ for (const v of entryViolations(entry))
201
+ olderViolations.push(v);
202
+ }
203
+ // Run all checks
204
+ const checks = [
205
+ () => checkProgressRegression(selfEval, prevSelfEval),
206
+ () => checkEmptyChangeWithPassing(selfEval),
207
+ () => checkSuccessWithRemainingCriteria(selfEval),
208
+ () => checkDuplicateConstraintDiscovery(selfEval, prevSelfEval, olderViolations),
209
+ () => checkRecurringViolation(selfEval, prevSelfEval, vaultEntries, currentRound),
210
+ () => checkRetractFreshConstraint(selfEval, prevSelfEval, currentRound),
211
+ ];
212
+ for (const run of checks) {
213
+ const flag = run();
214
+ if (flag)
215
+ flags.push(flag);
216
+ }
217
+ // Determine verdict from the most severe flag present
218
+ const hasError = flags.some((f) => f.severity === "error");
219
+ const hasWarn = flags.some((f) => f.severity === "warn");
220
+ let verdict;
221
+ if (hasError) {
222
+ verdict = "contradicted";
223
+ }
224
+ else if (hasWarn) {
225
+ verdict = "suspect";
226
+ }
227
+ else {
228
+ verdict = "trusted";
229
+ }
230
+ return makeVerificationResult({ verdict, flags });
231
+ }
232
+ //# sourceMappingURL=verification-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verification-gate.js","sourceRoot":"","sources":["../src/verification-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAE7E,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;qEAGqE;AACrE,SAAS,UAAU,CAAC,KAAiB;IACnC,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,EAAE,CAA4B,CAAC;IACtE,OAAQ,OAAO,CAAC,KAAgB,IAAI,CAAC,CAAC;AACxC,CAAC;AAED;+DAC+D;AAC/D,SAAS,eAAe,CAAC,KAAiB;IACxC,MAAM,KAAK,GAAG,KAAK,CAAC,qBAAqB,CAAC;IAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;IACrF,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,8EAA8E;AAC9E,8DAA8D;AAC9D,8EAA8E;AAE9E,SAAS,uBAAuB,CAC9B,QAAwB,EACxB,YAAmC;IAEnC,IAAI,CAAC,YAAY,EAAE,kBAAkB;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,CAAC,QAAQ,CAAC,kBAAkB;QAAE,OAAO,IAAI,CAAC;IAE9C,MAAM,YAAY,GAAG,YAAY,CAAC,kBAAkB,CAAC,iBAAiB,CAAC;IACvE,MAAM,YAAY,GAAG,QAAQ,CAAC,kBAAkB,CAAC,iBAAiB,CAAC;IAEnE,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,OAAO,YAAY,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACtF,sFAAsF;IACtF,IAAI,YAAY,GAAG,YAAY,IAAI,GAAG,GAAG,KAAK;QAAE,OAAO,IAAI,CAAC;IAE5D,OAAO,oBAAoB,CAAC;QAC1B,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,mBAAmB;QAC1B,KAAK,EAAE,qBAAqB;QAC5B,MAAM,EACJ,yBAAyB,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;YACtD,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,YAAY,GAAG,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;KACpF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,2BAA2B,CAClC,QAAwB;IAExB,MAAM,EAAE,GAAG,QAAQ,CAAC,kBAAkB,CAAC;IACvC,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAErB,MAAM,UAAU,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC;IACjD,MAAM,YAAY,GAChB,EAAE,CAAC,YAAY,KAAK,IAAI;QACxB,EAAE,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;QAC5B,EAAE,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;IAE7B,IAAI,CAAC,UAAU,IAAI,CAAC,YAAY,IAAI,CAAC,QAAQ,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAEnE,OAAO,oBAAoB,CAAC;QAC1B,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,oBAAoB;QAC3B,KAAK,EAAE,2BAA2B;QAClC,MAAM,EACJ,qEAAqE;YACrE,yCAAyC;KAC5C,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iCAAiC,CACxC,QAAwB;IAExB,IAAI,CAAC,QAAQ,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAEnC,MAAM,SAAS,GAAG,QAAQ,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IAC1E,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtD,OAAO,oBAAoB,CAAC;QAC1B,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,iCAAiC;QACxC,MAAM,EACJ,4BAA4B,SAAS,CAAC,MAAM,0BAA0B;YACtE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;KACnC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iCAAiC,CACxC,QAAwB,EACxB,YAAmC,EACnC,eAAyB;IAEzB,MAAM,UAAU,GAAG,QAAQ,CAAC,sBAAsB,CAAC;IACnD,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAExD,2CAA2C;IAC3C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,eAAe;QAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IAEnE,IAAI,YAAY,EAAE,CAAC;QACjB,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,sBAAsB,IAAI,EAAE,EAAE,CAAC;YAC1D,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QACpC,CAAC;QACD,0DAA0D;QAC1D,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,qBAAqB,EAAE,CAAC;YACnD,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACtC,OAAO,oBAAoB,CAAC;gBAC1B,QAAQ,EAAE,MAAM;gBAChB,KAAK,EAAE,wBAAwB;gBAC/B,KAAK,EAAE,gCAAgC;gBACvC,MAAM,EAAE,eAAe,CAAC,2CAA2C;aACpE,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,uBAAuB,CAC9B,QAAwB,EACxB,YAAmC,EACnC,YAA0B,EAC1B,YAAoB;IAEpB,MAAM,SAAS,GAAG,QAAQ,CAAC,qBAAqB,CAAC;IACjD,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtD,+DAA+D;IAC/D,MAAM,iBAAiB,GAAe,EAAE,CAAC;IAEzC,+DAA+D;IAC/D,4EAA4E;IAC5E,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,YAAY,GAAG,CAAC,CAAC,CAAC;QAClF,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,KAAK,GAAG,eAAe,CAAC,YAAY,CAAC,CAAC;YAC5C,IAAI,KAAK,CAAC,MAAM;gBAAE,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IAED,yCAAyC;IACzC,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,YAAY,CAAC,qBAAqB,CAAC;QACrD,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,2CAA2C;IAC3C,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAErE,iCAAiC;IACjC,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9C,6DAA6D;IAC7D,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACnB,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,OAAO,oBAAoB,CAAC;gBAC1B,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,uBAAuB;gBAC9B,KAAK,EAAE,qBAAqB;gBAC5B,MAAM,EACJ,yBAAyB,CAAC,yCAAyC;oBACnE,WAAW,YAAY,GAAG,CAAC,IAAI,YAAY,sBAAsB;aACpE,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,2BAA2B,CAClC,QAAwB,EACxB,YAAmC,EACnC,YAAoB;IAEpB,MAAM,SAAS,GAAG,QAAQ,CAAC,qBAAqB,CAAC;IACjD,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,IAAI,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IAE/B,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,sBAAsB,IAAI,EAAE,EAAE,CAAC;QAC1D,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,IAAI,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACrD,OAAO,oBAAoB,CAAC;gBAC1B,QAAQ,EAAE,MAAM;gBAChB,KAAK,EAAE,uBAAuB;gBAC9B,KAAK,EAAE,0BAA0B;gBACjC,MAAM,EACJ,0BAA0B,CAAC,sCAAsC;oBACjE,GAAG,YAAY,GAAG,CAAC,qCAAqC;aAC3D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAwB,EACxB,YAAoB,EACpB,YAA0B,EAC1B,eAAsC,IAAI;IAE1C,MAAM,KAAK,GAAuB,EAAE,CAAC;IAErC,6EAA6E;IAC7E,6CAA6C;IAC7C,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,KAAK,MAAM,CAAC,IAAI,eAAe,CAAC,KAAK,CAAC;YAAE,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,iBAAiB;IACjB,MAAM,MAAM,GAAyC;QACnD,GAAG,EAAE,CAAC,uBAAuB,CAAC,QAAQ,EAAE,YAAY,CAAC;QACrD,GAAG,EAAE,CAAC,2BAA2B,CAAC,QAAQ,CAAC;QAC3C,GAAG,EAAE,CAAC,iCAAiC,CAAC,QAAQ,CAAC;QACjD,GAAG,EAAE,CAAC,iCAAiC,CAAC,QAAQ,EAAE,YAAY,EAAE,eAAe,CAAC;QAChF,GAAG,EAAE,CAAC,uBAAuB,CAAC,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC;QACjF,GAAG,EAAE,CAAC,2BAA2B,CAAC,QAAQ,EAAE,YAAY,EAAE,YAAY,CAAC;KACxE,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC;QACnB,IAAI,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED,sDAAsD;IACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;IAEzD,IAAI,OAAsC,CAAC;IAC3C,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,GAAG,cAAc,CAAC;IAC3B,CAAC;SAAM,IAAI,OAAO,EAAE,CAAC;QACnB,OAAO,GAAG,SAAS,CAAC;IACtB,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,SAAS,CAAC;IACtB,CAAC;IAED,OAAO,sBAAsB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;AACpD,CAAC"}
package/loop_policy.json CHANGED
@@ -47,5 +47,36 @@
47
47
  "backend": {
48
48
  "vault_path": ".promptcraft/prompt_vault.json",
49
49
  "global_vault_path": "~/.promptcraft/global_vault.json"
50
+ },
51
+ "evolution": {
52
+ "max_discovered_constraints_per_round": 5,
53
+ "max_active_constraints": 15,
54
+ "max_objective_versions": 10,
55
+ "progress_stall_threshold": 0.05,
56
+ "progress_stall_rounds": 2,
57
+ "progress_mismatch_threshold": 0.3
58
+ },
59
+ "memory_injection": {
60
+ "enabled": true,
61
+ "min_rounds_between_injections": 1,
62
+ "phase_thresholds": {
63
+ "phase1": { "trigger": "round_1" },
64
+ "phase2": { "trigger": "progress", "threshold": 0.40 },
65
+ "phase3": { "trigger": "progress", "threshold": 0.70 }
66
+ },
67
+ "round_tiers": [
68
+ { "max_rounds": 10, "allowed_phases": [1] },
69
+ { "max_rounds": 20, "allowed_phases": [1, 3] },
70
+ { "max_rounds": 30, "allowed_phases": [1, 2, 3] }
71
+ ],
72
+ "dedup_threshold": 0.6,
73
+ "max_context_length": 2000,
74
+ "section_title": "### Background Context (Long-Term Memory)"
75
+ },
76
+ "memory_writeback": {
77
+ "enabled": true,
78
+ "max_feedback_entries": 5,
79
+ "max_discoveries_in_project": 3,
80
+ "write_on_outcomes": ["completed", "circuit_breaker", "max_rounds"]
50
81
  }
51
82
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopforge",
3
- "version": "1.3.1",
3
+ "version": "1.8.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",
@@ -24,7 +24,6 @@
24
24
  }
25
25
  },
26
26
  "bin": {
27
- "loopforge": "./dist/cli.js",
28
27
  "loopforge-mcp": "./dist/mcp-server.js"
29
28
  },
30
29
  "files": [
@@ -1,6 +1,6 @@
1
1
  ---
2
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.
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. Supports single-agent and multi-agent (AgentTool / Coordinator) scenarios.
4
4
  ---
5
5
 
6
6
  # Perception — Loop-Time Intelligence Skill
@@ -13,10 +13,15 @@ detection — maintaining cognitive stability across long-horizon loops.
13
13
  Works with Claude Code, Codex, and any MCP-capable host. Zero configuration
14
14
  beyond having `loopforge-mcp` registered as an MCP server.
15
15
 
16
+ **Multi-Agent:** When you spawn sub-agents (AgentTool) or orchestrate Workers
17
+ (Coordinator mode), LoopForge tracks delegation history, inherits constraints
18
+ across Workers, and injects structured summaries into subsequent prompts.
19
+ No separate mode required — LoopForge treats all agents the same.
20
+
16
21
  ## When to Activate
17
22
 
18
23
  Activate when the user says any of:
19
- - `/loop <task>` — start an autonomous multi-round loop
24
+ - `/perception <task>` — start an autonomous multi-round loop
20
25
  - "do this in a loop", "keep going until done", "iterate on this"
21
26
  - Any task that clearly needs 3+ rounds (audit, refactor, migrate, review-and-fix cycles)
22
27
 
@@ -26,20 +31,20 @@ round (e.g. "audit the entire codebase and fix every issue").
26
31
  ## Core Workflow
27
32
 
28
33
  ```
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
- │ After restart: loopforge_resume(loopId) │
41
- │ → picks up from last saved round │
42
- └─────────────────────────────────────────────────────┘
34
+ ┌──────────────────────────────────────────────────────────┐
35
+ │ 1. loopforge_start(task, constraints, maxRounds) │
36
+ │ → sessionId + Round 1 prompt │
37
+ │ │
38
+ │ 2. Execute the prompt (read, write, test, fix) │
39
+ │ Prepare a structured self-evaluation │
40
+ │ │
41
+ │ 3. loopforge_next(sessionId, evaluation, output?) │
42
+ │ → if prompt: go to step 2 │
43
+ │ → if prompt=null: loop ended, read stopReason │
44
+ │ │
45
+ │ After restart: loopforge_resume(loopId) │
46
+ │ → picks up from last saved round │
47
+ └──────────────────────────────────────────────────────────┘
43
48
  ```
44
49
 
45
50
  ### Step-by-step
@@ -60,18 +65,38 @@ Execute the compiled prompt exactly as you would any user task. Read files,
60
65
  write code, run tests, fix bugs. The prompt already contains the task scope,
61
66
  constraints, and quality expectations for this specific round.
62
67
 
63
- **CRITICAL: Every round's output MUST end with a self-evaluation block:**
64
- ```
65
- ---loopforge-eval
68
+ After executing, prepare a structured self-evaluation. Pass it as the
69
+ `evaluation` parameter to `loopforge_next` — do NOT embed it as a text block
70
+ in the output. The `evaluation` parameter is a typed object with the fields
71
+ described below.
72
+
73
+ **New (v1.7+): Pass evaluation as a structured tool parameter.**
74
+ ```json
66
75
  {
67
76
  "success": true,
68
77
  "output_summary": "Fixed 3 reentrancy bugs in withdraw() and deposit(). All 12 tests pass.",
69
78
  "constraint_violations": [],
70
- "should_continue": true
79
+ "should_continue": true,
80
+ "discovered_constraints": [],
81
+ "objective_refinement": "",
82
+ "emerged_subtasks": [],
83
+ "execution_evidence": {
84
+ "files_changed": ["contracts/Token.sol", "test/Token.test.ts"],
85
+ "test_results": {"passed": 24, "failed": 0, "skipped": 0},
86
+ "success_criteria_met": ["No reentrancy vectors remain"],
87
+ "success_criteria_remaining": ["Access control verified", "Overflow checks complete"],
88
+ "progress_estimate": 0.4
89
+ },
90
+ "retracted_constraints": [],
91
+ "revised_success_criteria": [],
92
+ "wrong_assumptions": []
71
93
  }
72
- ---end-loopforge-eval
73
94
  ```
74
95
 
96
+ **Legacy (still supported):** Embed a `---loopforge-eval` block in output text
97
+ when the agent cannot pass structured tool parameters. The new parameter form
98
+ is preferred — it's validated by the MCP client before reaching the server.
99
+
75
100
  **Field rules:**
76
101
 
77
102
  | Field | Type | Rule |
@@ -80,24 +105,37 @@ constraints, and quality expectations for this specific round.
80
105
  | `output_summary` | string | Specific, actionable. What was DONE this round — not what was attempted |
81
106
  | `constraint_violations` | string[] | Constraints the agent actually violated this round. Be honest — hiding violations corrupts the quality signal and defeats the circuit breaker |
82
107
  | `should_continue` | boolean | `false` ONLY when the ENTIRE task is complete. Partial progress = `true` |
83
-
84
- **Why this matters:** Without a valid `---loopforge-eval` block, extraction
85
- fails and the loop stops with `stopReason: stalled`. The circuit breaker
86
- uses `success` + `violations` to compute quality scores — lying here defeats
87
- the only mechanism that prevents infinite loops.
108
+ | `discovered_constraints` | string[] | **P0 (optional)** — New constraints discovered this round. They become active guardrails for future rounds. Example: `["All external calls must use SafeERC20"]`. Empty `[]` if none. |
109
+ | `objective_refinement` | string | **P1 (optional)** — If this round deepened your understanding of what the task is really about, describe the refinement. APPENDED to (never replaces) the original objective. Empty `""` if unchanged. |
110
+ | `emerged_subtasks` | string[] | **P2 (optional)** — Sub-problems that surfaced during execution and need separate attention. Feed into next-round task suggestions. Example: `["Audit upgrade proxy", "Verify timelock"]`. Empty `[]` if none. |
111
+ | `execution_evidence` | object | **P4 (recommended)** — Structured record of what actually happened. `files_changed` (string[]), `test_results` ({passed, failed, skipped} | null), `success_criteria_met` (string[]), `success_criteria_remaining` (string[]), `progress_estimate` (0.0–1.0). Use this to give LoopForge real visibility into your progress. |
112
+ | `retracted_constraints` | string[] | **P5 (optional)** — Constraints you now believe are wrong. Removed from active guardrails. Only retract with evidence. Empty `[]` if none. |
113
+ | `revised_success_criteria` | object[] | **P5 (optional)** — Success criteria that need reformulation. Array of `{old: string, new: string}`. Applied to Loop Objective. Empty `[]` if none. |
114
+ | `wrong_assumptions` | string[] | **P5 (optional)** — Assumptions from earlier rounds that turned out to be incorrect. Recorded as key lessons. Empty `[]` if none. |
115
+ | `worker_results` | object[] | **Multi-Agent (optional)** — Results of sub-agent / Worker delegations this round. Each entry: `{ agentId, subAgentType, subTask, resultSummary, success, discoveredConstraints? }`. Engine auto-records to delegation journal. Empty `[]` if no delegations. |
116
+
117
+ **Why this matters:** The evaluation is validated by the MCP client before
118
+ reaching the server — a missing or malformed evaluation causes an immediate
119
+ error, not a silent stall. The circuit breaker uses `success` + `violations`
120
+ to compute quality scores — lying here defeats the only mechanism that
121
+ prevents infinite loops. The optional fields (P0–P5) enable cognitive
122
+ evolution: discovering constraints, deepening understanding, surfacing
123
+ sub-problems, tracking real progress, and correcting wrong assumptions as
124
+ the loop executes.
88
125
 
89
126
  **Step 3 — Advance to next round:**
90
127
  ```
91
128
  Call loopforge_next with:
92
- sessionId: from loopforge_start
93
- output: your FULL output from this round (including the eval block)
129
+ sessionId: from loopforge_start
130
+ evaluation: REQUIRED — structured self-evaluation object (see field table below)
131
+ output: OPTIONAL — raw output text for audit trail (can be omitted)
94
132
  ```
95
133
 
96
134
  If the result has `prompt: null`, the loop has ended. Read `stopReason`:
97
135
  - `task_complete` — you reported should_continue=false. Work is done.
98
136
  - `circuit_breaker` — quality flat or declining for 3+ rounds. Review your approach.
99
137
  - `max_rounds` — hit the round limit. Decide whether to extend or accept.
100
- - `stalled` — no valid self-eval block found. Check your output format.
138
+ - `stalled` — no valid self-evaluation provided. Check your evaluation parameter.
101
139
 
102
140
  If the result has a non-null `prompt`, execute it and repeat from Step 2.
103
141
 
@@ -114,6 +152,51 @@ If the result has a non-null `prompt`, execute it and repeat from Step 2.
114
152
  | `loopforge_resume` | Resume a loop after process restart | `loopId` | next `prompt` or `null` + `stopReason` |
115
153
  | `loopforge_health` | Check loop health mid-run | `loopId` | goal alignment, constraint integrity, drift, strategy |
116
154
 
155
+ ## Delegation Helpers (AgentTool Mode)
156
+
157
+ When you spawn sub-agents via `AgentTool` (Explore, General-purpose, Plan)
158
+ during a loop round, use these helpers to improve delegation quality:
159
+
160
+ **Before delegating:**
161
+ 1. **Filter constraints** — not all active constraints apply to every sub-agent.
162
+ An Explore agent searching for deprecated APIs doesn't need "all files must
163
+ have a license header." Use `filterConstraintsForSubTask(allConstraints, subTask)`
164
+ to get only the relevant subset.
165
+ 2. **Format the prompt** — use `formatDelegationPrompt(subTask, subAgentType,
166
+ relevantConstraints, options?)` to produce a self-contained prompt. This is
167
+ critical: sub-agents cannot see your conversation. Every prompt must stand
168
+ alone — no "based on above," no "continue from previous."
169
+
170
+ **After delegating (in your self-evaluation):**
171
+ Include `worker_results` in your evaluation to record what you delegated.
172
+ The engine auto-detects this field and writes delegation journals to the vault:
173
+
174
+ ```json
175
+ {
176
+ "worker_results": [
177
+ {
178
+ "agentId": "abc123",
179
+ "subAgentType": "explore",
180
+ "subTask": "Search for deprecated API usage in src/",
181
+ "resultSummary": "Found 12 deprecated calls across 8 files",
182
+ "success": true,
183
+ "discoveredConstraints": ["All API calls must be versioned"]
184
+ }
185
+ ]
186
+ }
187
+ ```
188
+
189
+ This feeds into the delegation history table displayed in future rounds.
190
+ Constraints discovered by sub-agents flow into the active constraint set
191
+ automatically — they appear in future prompts alongside main-agent constraints.
192
+ Delegation recording is lightweight — it's the main agent's memory,
193
+ not sub-agent memory.
194
+
195
+ **Important:** These helpers are optional. If your sub-task is trivial (e.g.
196
+ "read file X and report line 42"), a raw prompt is fine. Use the helpers when
197
+ sub-tasks involve constraints, specific output formats, or results worth
198
+ remembering across rounds.
199
+
117
200
  ## Quality Signals (Read the Room)
118
201
 
119
202
  The prompt changes between rounds based on your trajectory. Pay attention to:
@@ -138,7 +221,8 @@ The prompt changes between rounds based on your trajectory. Pay attention to:
138
221
 
139
222
  ## Rules
140
223
 
141
- 1. **Never skip the eval block.** No exceptions. If you forget, the loop stalls.
224
+ 1. **Always pass the evaluation parameter.** `loopforge_next` requires it.
225
+ If you omit it, the MCP client will reject the call with a schema error.
142
226
  2. **Be honest in self-evaluation.** Lying about success or hiding violations
143
227
  produces a false quality signal. The circuit breaker exists to stop bad
144
228
  loops — if you fake quality=5 every round, it fires anyway.
@@ -154,7 +238,7 @@ The prompt changes between rounds based on your trajectory. Pay attention to:
154
238
  ## Example
155
239
 
156
240
  ```
157
- User: /loop "Audit the ERC20 token in contracts/Token.sol for security issues"
241
+ User: /perception "Audit the ERC20 token in contracts/Token.sol for security issues"
158
242
 
159
243
  Agent:
160
244
  → loopforge_start({ task: "Audit ERC20 token in contracts/Token.sol for security issues",
@@ -162,33 +246,41 @@ Agent:
162
246
  constraints: ["must not break existing tests", "follow check-effects-interactions"] })
163
247
  ← { sessionId: "abc-123", round: 1, prompt: "## LoopForge Loop Compile — Round 1\n...", level: "l2" }
164
248
 
165
- [Executes prompt: reads Token.sol, identifies 4 issues, writes audit notes]
166
-
167
- Output ends with:
168
- ---loopforge-eval
169
- {"success":false,"output_summary":"Found 4 potential issues: 2 reentrancy, 1 overflow, 1 access control. Not yet fixed.","constraint_violations":[],"should_continue":true}
170
- ---end-loopforge-eval
249
+ [Executes prompt: reads Token.sol, identifies 4 issues, discovers a new constraint]
171
250
 
172
- → loopforge_next({ sessionId: "abc-123", output: <full output> })
251
+ → loopforge_next({ sessionId: "abc-123",
252
+ evaluation: {
253
+ success: false,
254
+ output_summary: "Found 4 potential issues: 2 reentrancy, 1 overflow, 1 access control. Not yet fixed.",
255
+ constraint_violations: [],
256
+ should_continue: true,
257
+ discovered_constraints: ["All _mint() calls must emit Transfer event per ERC20 spec"]
258
+ } })
173
259
  ← { sessionId: "abc-123", round: 2, prompt: "## LoopForge Loop Compile — Round 2\n...", level: "l1" }
174
260
 
175
- [Executes prompt: fixes 3 issues, 1 needs more investigation]
176
-
177
- ---loopforge-eval
178
- {"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}
179
- ---end-loopforge-eval
180
-
181
- → loopforge_next({ sessionId: "abc-123", output: <full output> })
182
- ← { sessionId: "abc-123", round: 3, prompt: "## LoopForge Loop Compile — Round 3\n...", level: "l0" }
183
-
184
- [Executes prompt: documents access control issue for user decision, all fixes pass tests]
185
-
186
- ---loopforge-eval
187
- {"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}
188
- ---end-loopforge-eval
189
-
190
- → loopforge_next({ sessionId: "abc-123", output: <full output> })
261
+ [Executes prompt: fixes 3 issues, deepens understanding of access control problem]
262
+
263
+ → loopforge_next({ sessionId: "abc-123",
264
+ evaluation: {
265
+ success: false,
266
+ output_summary: "Fixed reentrancy in withdraw() and overflow in calcReward(). Access control in setOwner() needs design discussion — discovered it's part of a larger upgradeability concern.",
267
+ constraint_violations: [],
268
+ should_continue: true,
269
+ objective_refinement: "Access control audit scope expanded: setOwner() is unprotected because the contract follows an upgradeable proxy pattern where owner is set via initializer — need to verify the initializer guard and proxy admin separately",
270
+ emerged_subtasks: ["Audit upgrade proxy initialization flow", "Verify proxy admin is not renounced without recovery path"]
271
+ } })
272
+ ← { sessionId: "abc-123", round: 3, prompt: "## LoopForge Loop Compile — Round 3\n Suggested Next Task: Audit upgrade proxy initialization flow; Verify proxy admin is not renounced without recovery path\n...", level: "l0" }
273
+
274
+ [Executes prompt: audits proxy pattern, documents findings, all fixes pass tests]
275
+
276
+ → loopforge_next({ sessionId: "abc-123",
277
+ evaluation: {
278
+ success: true,
279
+ output_summary: "All fixable issues resolved. Proxy initialization verified — initializer modifier prevents double-init. Proxy admin held by multisig — low risk. 24/24 tests pass.",
280
+ constraint_violations: [],
281
+ should_continue: false
282
+ } })
191
283
  ← { sessionId: "abc-123", round: 3, prompt: null, stopReason: "task_complete", quality: 5 }
192
284
 
193
- Reports to user: "Audit complete in 3 rounds. 3 issues fixed, 1 design question flagged."
285
+ Reports to user: "Audit complete in 3 rounds. 3 issues fixed, 1 design question flagged. Discovered 1 new constraint during audit. Objective deepened to include proxy pattern verification."
194
286
  ```
package/dist/adapter.d.ts DELETED
@@ -1,17 +0,0 @@
1
- /** LoopForge-loop_compile — Sub-agent adapter (unified entry point).
2
- *
3
- * This is the single entry point when LoopForge is invoked as a sub-agent.
4
- * It wraps the Engine, routes by mode, and always prepends a compact health line.
5
- *
6
- * Three modes (v1.0):
7
- * loop_compile — Per-iteration prompt compiler (primary entry point)
8
- * feedback — Record execution results → quality scoring → vault persistence
9
- * review — Audit prompt quality (structural checks + constraint compliance)
10
- *
11
- * build is an internal path (loop_compile L2 delegation) — not an exposed mode.
12
- */
13
- import { type LoopForgeRequest } from "./protocol.js";
14
- import { LoopForgeEngine } from "./engine.js";
15
- export declare function handle(requestInput: string | Record<string, unknown> | LoopForgeRequest, engine?: LoopForgeEngine): string;
16
- export declare function main(): void;
17
- //# sourceMappingURL=adapter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,eAAe,EAGhB,MAAM,aAAa,CAAC;AAiBrB,wBAAgB,MAAM,CACpB,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB,EACjE,MAAM,CAAC,EAAE,eAAe,GACvB,MAAM,CAwER;AAsJD,wBAAgB,IAAI,IAAI,IAAI,CA8B3B"}