loopforge 3.8.1 → 3.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -171
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/loop_policy.json +59 -59
- package/package.json +67 -67
- package/skills/perception/SKILL.md +220 -370
package/README.md
CHANGED
|
@@ -1,171 +1,123 @@
|
|
|
1
|
-
# LoopForge
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
the
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
##
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
and retryable `evaluation_invalid` responses.
|
|
125
|
-
- One committed-round history for the compiler, contracts, gates, Replay,
|
|
126
|
-
Audit, and Metrics.
|
|
127
|
-
- One Canonical State for prompts, the optional state file, and current-status
|
|
128
|
-
cognition.
|
|
129
|
-
- Evidence-backed accept, reject, backtrack, and terminate decisions, including
|
|
130
|
-
Round Contract and workspace-restore checks. A backtrack carries a derived
|
|
131
|
-
Recovery Brief — trigger rule, restore point, redo round ID, failed
|
|
132
|
-
approaches, and falsified assumptions — sourced from committed rounds plus
|
|
133
|
-
the in-flight attempt (never rejected payloads); the redo reuses the round
|
|
134
|
-
ID and its commit retires the brief.
|
|
135
|
-
- L0, L1, and L2 prompt density, five-state sub-goals with explicit
|
|
136
|
-
`subgoal_updates` transitions (active `sg-` IDs only; done/canceled are
|
|
137
|
-
terminal), constraint lifecycle, milestones, and agent-requested emphasis
|
|
138
|
-
(by stable id or exact text) or confusion points. Prompts and the state file
|
|
139
|
-
render active sub-goals only, capped by policy; the state file is grouped
|
|
140
|
-
into Current / Recent / Historical Summary tiers with derived metadata
|
|
141
|
-
(round, attempt, state hash) and is byte-identical when regenerated from the
|
|
142
|
-
Vault — its content depends on committed facts, not on which prompt level
|
|
143
|
-
compiled.
|
|
144
|
-
- Separate Replay and Audit views. Replay answers what happened; Audit checks
|
|
145
|
-
evidence and completeness.
|
|
146
|
-
- Durable sessions with atomic round documents, sequence checks, owned locks,
|
|
147
|
-
renewable leases, pause, resume, and idempotent recovery.
|
|
148
|
-
- Nine MCP tools: `start`, `next`, `status`, `stop`, `pause`, `resume`, `replay`,
|
|
149
|
-
`gate_check`, and `gate_resolve`. The two gate tools are opt-in
|
|
150
|
-
(`policy.gate.enabled`, default false): hidden from `tools/list`, structured
|
|
151
|
-
preflight via `gate_check`, round-blocking on unapproved `gate_ids`
|
|
152
|
-
citations.
|
|
153
|
-
- Zero runtime dependencies. Policy controls thresholds, budgets, and intervals.
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## Development
|
|
158
|
-
|
|
159
|
-
```bash
|
|
160
|
-
npm run check
|
|
161
|
-
npm test
|
|
162
|
-
npm pack --dry-run --json
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
The protocol schema in `../loopforge-protocol.json` is generated from `src/protocol.ts`. Do not edit it by hand.
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
## License
|
|
170
|
-
|
|
171
|
-
MIT
|
|
1
|
+
# LoopForge package
|
|
2
|
+
|
|
3
|
+
The `loopforge` package is the TypeScript runtime behind LoopForge. It keeps
|
|
4
|
+
round state durable, collects machine evidence, verifies submitted claims, and
|
|
5
|
+
compiles the next prompt. The external coding Agent still owns planning, file
|
|
6
|
+
changes, tool use, and execution.
|
|
7
|
+
|
|
8
|
+
For the product model and the contract mental model, read the
|
|
9
|
+
[root README](../README.md) or [中文说明](../README.zh-CN.md). This document is
|
|
10
|
+
the package and integration reference.
|
|
11
|
+
|
|
12
|
+
**Requirements:** Node.js >= 18. Zero runtime dependencies. The package version
|
|
13
|
+
is defined only by the `version` field in `package.json`.
|
|
14
|
+
|
|
15
|
+
## Install and run
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g loopforge
|
|
19
|
+
loopforge init --client claude
|
|
20
|
+
claude mcp add loopforge -- npx loopforge mcp
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The CLI provides the following entry points:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
loopforge mcp
|
|
27
|
+
loopforge init --client claude|codex|generic [--target DIR] [--force]
|
|
28
|
+
loopforge doctor [--json]
|
|
29
|
+
loopforge inspect LOOP_ID [--round N] [--prompt] [--json]
|
|
30
|
+
loopforge explain LOOP_ID [--round N] [--json]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`loopforge mcp` starts the synchronous MCP server. `init` installs the client
|
|
34
|
+
configuration, `doctor` reports local readiness, `inspect` reads persisted loop
|
|
35
|
+
state, and `explain` shows why a committed round received its disposition.
|
|
36
|
+
|
|
37
|
+
## MCP integration
|
|
38
|
+
|
|
39
|
+
The MCP server exposes nine tools:
|
|
40
|
+
|
|
41
|
+
- `loopforge_start` creates a session and returns the first prompt.
|
|
42
|
+
- `loopforge_next` submits the structured evaluation for the held round.
|
|
43
|
+
- `loopforge_status` returns session, loop, audit, or explain views.
|
|
44
|
+
- `loopforge_stop` intentionally stops a session.
|
|
45
|
+
- `loopforge_pause` pauses a session at a round boundary.
|
|
46
|
+
- `loopforge_resume` reconstructs a durable session.
|
|
47
|
+
- `loopforge_replay` reads the committed timeline and round diffs.
|
|
48
|
+
- `loopforge_gate_check` preflights a high-risk action.
|
|
49
|
+
- `loopforge_gate_resolve` records the decision for an opened user gate.
|
|
50
|
+
|
|
51
|
+
The two gate tools are opt-in through `policy.gate.enabled` and are hidden from
|
|
52
|
+
`tools/list` when disabled. A gate decision is an auditable process record. It
|
|
53
|
+
does not prove that a human was present because the Agent submits the resolve
|
|
54
|
+
call.
|
|
55
|
+
|
|
56
|
+
Every `loopforge_next` submission must include the four strict evaluation
|
|
57
|
+
fields: `success`, `output_summary`, `constraint_violations`, and
|
|
58
|
+
`should_continue`. `round_contract`, `subgoal_updates`, and
|
|
59
|
+
`execution_report.contract_item_claims` are also strict structural boundaries.
|
|
60
|
+
Malformed payloads return a retryable error for the same `roundId` without
|
|
61
|
+
writing session state, a round, gate records, rejection counters, or metrics.
|
|
62
|
+
Agent reports remain claims. Only independent observations can support a
|
|
63
|
+
verified fact.
|
|
64
|
+
|
|
65
|
+
## TypeScript API
|
|
66
|
+
|
|
67
|
+
The package exports the runtime in separate entry points:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
loopforge protocol types, policy, store, compiler, engine, evidence,
|
|
71
|
+
transactions, metrics, and MCP classes
|
|
72
|
+
loopforge/compiler compiler helpers
|
|
73
|
+
loopforge/replay ReplayBackend
|
|
74
|
+
loopforge/mcp MCP server entry point
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The main exports include `createEngine` and `LoopForgeEngine` for an in-process
|
|
78
|
+
engine, `FileLoopStore` for durable JSON storage, `compileLoop` for compiling a
|
|
79
|
+
prompt from committed facts, `ReplayBackend` for read-only history queries,
|
|
80
|
+
`McpServer` for the MCP transport, and `SessionManager` for durable MCP
|
|
81
|
+
sessions. Type declarations are emitted alongside the runtime in `dist/`.
|
|
82
|
+
|
|
83
|
+
Example import:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { createEngine, FileLoopStore, compileLoop } from "loopforge";
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Use the generated `.d.ts` files in `dist/` for the exact signatures and input
|
|
90
|
+
types. The public protocol constructors and types are exported from the main
|
|
91
|
+
entry point.
|
|
92
|
+
|
|
93
|
+
## Persistence and policy
|
|
94
|
+
|
|
95
|
+
LoopForge stores durable loop data under `.loopforge/loops/` and derived human
|
|
96
|
+
state under `.loopforge/state/`. Committed typed round documents are the source
|
|
97
|
+
of truth. The state file can be regenerated and must not be treated as a second
|
|
98
|
+
history.
|
|
99
|
+
|
|
100
|
+
Runtime behavior is controlled by `loop_policy.json`. Evidence commands are
|
|
101
|
+
explicitly configured, run without a shell, and restricted to the workspace.
|
|
102
|
+
The default policy keeps the optional user gate disabled.
|
|
103
|
+
|
|
104
|
+
## Development
|
|
105
|
+
|
|
106
|
+
Run these commands from this directory:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm run check
|
|
110
|
+
npm run build
|
|
111
|
+
npm test
|
|
112
|
+
npm pack --dry-run --json
|
|
113
|
+
npm run verify:artifacts
|
|
114
|
+
git diff --check
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The build generates `../loopforge-protocol.json` and `dist/`. Change protocol
|
|
118
|
+
types in `src/protocol.ts` first, then run the build. Do not edit generated
|
|
119
|
+
artifacts by hand.
|
|
120
|
+
|
|
121
|
+
## License
|
|
122
|
+
|
|
123
|
+
MIT
|
package/dist/version.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Generated by scripts/sync-version.mjs — do not edit by hand.
|
|
2
2
|
* Single version source: the `version` field of package.json.
|
|
3
3
|
* CLI, MCP server info, and doctor reports all read this constant. */
|
|
4
|
-
export declare const VERSION = "3.8.
|
|
4
|
+
export declare const VERSION = "3.8.2";
|
|
5
5
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Generated by scripts/sync-version.mjs — do not edit by hand.
|
|
2
2
|
* Single version source: the `version` field of package.json.
|
|
3
3
|
* CLI, MCP server info, and doctor reports all read this constant. */
|
|
4
|
-
export const VERSION = "3.8.
|
|
4
|
+
export const VERSION = "3.8.2";
|
|
5
5
|
//# sourceMappingURL=version.js.map
|
package/loop_policy.json
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "4",
|
|
3
|
-
"constraints": {
|
|
4
|
-
"retire_window": 3
|
|
5
|
-
},
|
|
6
|
-
"summary": {
|
|
7
|
-
"window": 5,
|
|
8
|
-
"milestone_interval": 20
|
|
9
|
-
},
|
|
10
|
-
"engine": {
|
|
11
|
-
"stall_lookback_rounds": 3,
|
|
12
|
-
"max_rounds": 200,
|
|
13
|
-
"enforcement_escalation_enabled": true,
|
|
14
|
-
"backtrack_enabled": true,
|
|
15
|
-
"backtrack_max_depth": 3,
|
|
16
|
-
"backtrack_preserve_discoveries": true,
|
|
17
|
-
"unverified_claim_streak_limit": 3
|
|
18
|
-
},
|
|
19
|
-
"prompt": {
|
|
20
|
-
"l0_max_chars": 3000,
|
|
21
|
-
"l1_max_chars": 7000,
|
|
22
|
-
"l2_max_chars": 18000,
|
|
23
|
-
"l2_pointer_enabled": true,
|
|
24
|
-
"max_emphasize_l2": 5,
|
|
25
|
-
"max_emphasize_l1": 3,
|
|
26
|
-
"max_confusion_points": 3
|
|
27
|
-
},
|
|
28
|
-
"backend": {
|
|
29
|
-
"root_dir": ".loopforge"
|
|
30
|
-
},
|
|
31
|
-
"evolution": {
|
|
32
|
-
"max_discovered_constraints_per_round": 5,
|
|
33
|
-
"max_active_constraints": 15,
|
|
34
|
-
"max_objective_versions": 10,
|
|
35
|
-
"progress_stall_threshold": 0.05,
|
|
36
|
-
"max_active_subgoals": 12
|
|
37
|
-
},
|
|
38
|
-
"checkpoint": {
|
|
39
|
-
"outcome_max_chars": 200
|
|
40
|
-
},
|
|
41
|
-
"state_file": {
|
|
42
|
-
"enabled": true,
|
|
43
|
-
"directory": ".loopforge/state"
|
|
44
|
-
},
|
|
45
|
-
"evidence": {
|
|
46
|
-
"providers": [
|
|
47
|
-
"git"
|
|
48
|
-
],
|
|
49
|
-
"timeout_ms": 120000,
|
|
50
|
-
"commands": []
|
|
51
|
-
},
|
|
52
|
-
"mcp": {
|
|
53
|
-
"session_lease_ms": 30000,
|
|
54
|
-
"session_lease_renew_interval_ms": 10000
|
|
55
|
-
},
|
|
56
|
-
"gate": {
|
|
57
|
-
"enabled": false
|
|
58
|
-
}
|
|
59
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"version": "4",
|
|
3
|
+
"constraints": {
|
|
4
|
+
"retire_window": 3
|
|
5
|
+
},
|
|
6
|
+
"summary": {
|
|
7
|
+
"window": 5,
|
|
8
|
+
"milestone_interval": 20
|
|
9
|
+
},
|
|
10
|
+
"engine": {
|
|
11
|
+
"stall_lookback_rounds": 3,
|
|
12
|
+
"max_rounds": 200,
|
|
13
|
+
"enforcement_escalation_enabled": true,
|
|
14
|
+
"backtrack_enabled": true,
|
|
15
|
+
"backtrack_max_depth": 3,
|
|
16
|
+
"backtrack_preserve_discoveries": true,
|
|
17
|
+
"unverified_claim_streak_limit": 3
|
|
18
|
+
},
|
|
19
|
+
"prompt": {
|
|
20
|
+
"l0_max_chars": 3000,
|
|
21
|
+
"l1_max_chars": 7000,
|
|
22
|
+
"l2_max_chars": 18000,
|
|
23
|
+
"l2_pointer_enabled": true,
|
|
24
|
+
"max_emphasize_l2": 5,
|
|
25
|
+
"max_emphasize_l1": 3,
|
|
26
|
+
"max_confusion_points": 3
|
|
27
|
+
},
|
|
28
|
+
"backend": {
|
|
29
|
+
"root_dir": ".loopforge"
|
|
30
|
+
},
|
|
31
|
+
"evolution": {
|
|
32
|
+
"max_discovered_constraints_per_round": 5,
|
|
33
|
+
"max_active_constraints": 15,
|
|
34
|
+
"max_objective_versions": 10,
|
|
35
|
+
"progress_stall_threshold": 0.05,
|
|
36
|
+
"max_active_subgoals": 12
|
|
37
|
+
},
|
|
38
|
+
"checkpoint": {
|
|
39
|
+
"outcome_max_chars": 200
|
|
40
|
+
},
|
|
41
|
+
"state_file": {
|
|
42
|
+
"enabled": true,
|
|
43
|
+
"directory": ".loopforge/state"
|
|
44
|
+
},
|
|
45
|
+
"evidence": {
|
|
46
|
+
"providers": [
|
|
47
|
+
"git"
|
|
48
|
+
],
|
|
49
|
+
"timeout_ms": 120000,
|
|
50
|
+
"commands": []
|
|
51
|
+
},
|
|
52
|
+
"mcp": {
|
|
53
|
+
"session_lease_ms": 30000,
|
|
54
|
+
"session_lease_renew_interval_ms": 10000
|
|
55
|
+
},
|
|
56
|
+
"gate": {
|
|
57
|
+
"enabled": false
|
|
58
|
+
}
|
|
59
|
+
}
|
package/package.json
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "loopforge",
|
|
3
|
-
"version": "3.8.
|
|
4
|
-
"description": "External cognitive infrastructure for AI coding agents — breaks the summary cascade, provides independent verification, and enables model-directed prompt prioritization for 100+ round agent loops.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"import": "./dist/index.js",
|
|
11
|
-
"types": "./dist/index.d.ts"
|
|
12
|
-
},
|
|
13
|
-
"./compiler": {
|
|
14
|
-
"import": "./dist/loop-compiler.js",
|
|
15
|
-
"types": "./dist/loop-compiler.d.ts"
|
|
16
|
-
},
|
|
17
|
-
"./replay": {
|
|
18
|
-
"import": "./dist/replay.js",
|
|
19
|
-
"types": "./dist/replay.d.ts"
|
|
20
|
-
},
|
|
21
|
-
"./mcp": {
|
|
22
|
-
"import": "./dist/mcp/server.js",
|
|
23
|
-
"types": "./dist/mcp/server.d.ts"
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
"bin": {
|
|
27
|
-
"loopforge": "dist/cli.js"
|
|
28
|
-
},
|
|
29
|
-
"files": [
|
|
30
|
-
"dist/",
|
|
31
|
-
"!dist/tests/",
|
|
32
|
-
"skills",
|
|
33
|
-
"loop_policy.json",
|
|
34
|
-
"LICENSE"
|
|
35
|
-
],
|
|
36
|
-
"scripts": {
|
|
37
|
-
"build": "node scripts/sync-version.mjs && tsc && node scripts/trim-dist.mjs && node dist/generate-schema.js && node scripts/trim-dist.mjs",
|
|
38
|
-
"generate-schema": "node scripts/sync-version.mjs && tsc && node scripts/trim-dist.mjs && node dist/generate-schema.js && node scripts/trim-dist.mjs",
|
|
39
|
-
"test": "node scripts/sync-version.mjs && tsc && node scripts/trim-dist.mjs && node dist/generate-schema.js && node scripts/trim-dist.mjs && node --test --test-concurrency=1 dist/tests/*.test.js",
|
|
40
|
-
"test:watch": "node scripts/sync-version.mjs && tsc && node scripts/trim-dist.mjs && node --test --watch dist/tests/*.test.js",
|
|
41
|
-
"check": "node scripts/sync-version.mjs && tsc --noEmit",
|
|
42
|
-
"verify:artifacts": "node scripts/verify-artifacts.mjs",
|
|
43
|
-
"prepack": "npm run verify:artifacts && npm run build"
|
|
44
|
-
},
|
|
45
|
-
"repository": {
|
|
46
|
-
"type": "git",
|
|
47
|
-
"url": "git+https://github.com/kyrielrving11/LoopForge.git"
|
|
48
|
-
},
|
|
49
|
-
"keywords": [
|
|
50
|
-
"cognitive-state",
|
|
51
|
-
"ai-agent",
|
|
52
|
-
"durable-agent",
|
|
53
|
-
"claude-code",
|
|
54
|
-
"llm",
|
|
55
|
-
"cognitive-stability",
|
|
56
|
-
"constraint-management",
|
|
57
|
-
"mcp"
|
|
58
|
-
],
|
|
59
|
-
"engines": {
|
|
60
|
-
"node": ">=18"
|
|
61
|
-
},
|
|
62
|
-
"license": "MIT",
|
|
63
|
-
"devDependencies": {
|
|
64
|
-
"@types/node": "^20.0.0",
|
|
65
|
-
"typescript": "^5.4.0"
|
|
66
|
-
}
|
|
67
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "loopforge",
|
|
3
|
+
"version": "3.8.2",
|
|
4
|
+
"description": "External cognitive infrastructure for AI coding agents — breaks the summary cascade, provides independent verification, and enables model-directed prompt prioritization for 100+ round agent loops.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./compiler": {
|
|
14
|
+
"import": "./dist/loop-compiler.js",
|
|
15
|
+
"types": "./dist/loop-compiler.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./replay": {
|
|
18
|
+
"import": "./dist/replay.js",
|
|
19
|
+
"types": "./dist/replay.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./mcp": {
|
|
22
|
+
"import": "./dist/mcp/server.js",
|
|
23
|
+
"types": "./dist/mcp/server.d.ts"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"bin": {
|
|
27
|
+
"loopforge": "dist/cli.js"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist/",
|
|
31
|
+
"!dist/tests/",
|
|
32
|
+
"skills",
|
|
33
|
+
"loop_policy.json",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "node scripts/sync-version.mjs && tsc && node scripts/trim-dist.mjs && node dist/generate-schema.js && node scripts/trim-dist.mjs",
|
|
38
|
+
"generate-schema": "node scripts/sync-version.mjs && tsc && node scripts/trim-dist.mjs && node dist/generate-schema.js && node scripts/trim-dist.mjs",
|
|
39
|
+
"test": "node scripts/sync-version.mjs && tsc && node scripts/trim-dist.mjs && node dist/generate-schema.js && node scripts/trim-dist.mjs && node --test --test-concurrency=1 dist/tests/*.test.js",
|
|
40
|
+
"test:watch": "node scripts/sync-version.mjs && tsc && node scripts/trim-dist.mjs && node --test --watch dist/tests/*.test.js",
|
|
41
|
+
"check": "node scripts/sync-version.mjs && tsc --noEmit",
|
|
42
|
+
"verify:artifacts": "node scripts/verify-artifacts.mjs",
|
|
43
|
+
"prepack": "npm run verify:artifacts && npm run build"
|
|
44
|
+
},
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/kyrielrving11/LoopForge.git"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"cognitive-state",
|
|
51
|
+
"ai-agent",
|
|
52
|
+
"durable-agent",
|
|
53
|
+
"claude-code",
|
|
54
|
+
"llm",
|
|
55
|
+
"cognitive-stability",
|
|
56
|
+
"constraint-management",
|
|
57
|
+
"mcp"
|
|
58
|
+
],
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=18"
|
|
61
|
+
},
|
|
62
|
+
"license": "MIT",
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/node": "^20.0.0",
|
|
65
|
+
"typescript": "^5.4.0"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -1,414 +1,264 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: perception
|
|
3
|
-
description: Drive
|
|
3
|
+
description: Drive multi-round coding tasks through LoopForge MCP so objectives, constraints, evidence, and decisions survive context loss and restarts. The external Agent remains responsible for planning, file changes, tools, and execution.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Perception
|
|
7
7
|
|
|
8
|
-
Use LoopForge when a
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
Use LoopForge when a task spans several meaningful work slices, must survive a
|
|
9
|
+
restart or context loss, or needs an auditable distinction between Agent claims
|
|
10
|
+
and machine-verified facts.
|
|
11
11
|
|
|
12
|
-
LoopForge has one factual source,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
and decides how to reason.
|
|
12
|
+
LoopForge has one factual source, committed typed round documents in the Vault,
|
|
13
|
+
and one cognitive source, Canonical State compiled from those documents. The
|
|
14
|
+
Agent still decides what to do and how to reason.
|
|
16
15
|
|
|
17
16
|
## Start
|
|
18
17
|
|
|
18
|
+
Call `loopforge_status` with `view: "all"` before starting. Reuse an existing
|
|
19
|
+
session for the same objective instead of opening a second loop.
|
|
20
|
+
|
|
19
21
|
Call `loopforge_start` with:
|
|
20
22
|
|
|
21
|
-
- `task`: the complete user objective
|
|
22
|
-
- `constraints`: hard boundaries that must survive every round
|
|
23
|
-
- `maxRounds
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
one
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
23
|
+
- `task`: the complete user objective;
|
|
24
|
+
- `constraints`: hard boundaries that must survive every round;
|
|
25
|
+
- optional `maxRounds`, `domain`, `loopId`, and `planSource`.
|
|
26
|
+
|
|
27
|
+
Keep the returned `sessionId`, `roundId`, prompt, and level. Pass the latest
|
|
28
|
+
`roundId` to every `loopforge_next`; it anchors the submission to the exact
|
|
29
|
+
round being reported.
|
|
30
|
+
|
|
31
|
+
## What is a round?
|
|
32
|
+
|
|
33
|
+
A round is one coherent work slice that can be described, checked, and
|
|
34
|
+
disposed of at the next boundary. It is not a fixed number of files, tokens,
|
|
35
|
+
commits, or minutes. A capable Agent may complete a large change in one round
|
|
36
|
+
when the change shares one objective, one evidence story, and one recovery
|
|
37
|
+
path. Split it when those boundaries diverge.
|
|
38
|
+
|
|
39
|
+
Before choosing the slice, ask:
|
|
40
|
+
|
|
41
|
+
1. **Coherence:** does the work serve one immediate objective rather than
|
|
42
|
+
several unrelated goals?
|
|
43
|
+
2. **Verifiability:** can the result and its hard constraints be checked with
|
|
44
|
+
the available tests, commands, or other machine observations?
|
|
45
|
+
3. **Disposition:** will the boundary produce a clear continuation, stop,
|
|
46
|
+
blocker, rejection, or recovery decision?
|
|
47
|
+
4. **Recovery:** can the slice be safely retried or rolled back without
|
|
48
|
+
invalidating unrelated work?
|
|
49
|
+
|
|
50
|
+
Make a round larger when changes are tightly coupled and can be verified
|
|
51
|
+
together. Make it smaller when uncertainty, external effects, evidence gaps,
|
|
52
|
+
or rollback risk is high. Do not combine independent objectives merely because
|
|
53
|
+
the Agent can edit them in one context. Do not split a single atomic change
|
|
54
|
+
only to create more round records.
|
|
55
|
+
|
|
56
|
+
At the end of a round, inspect the actual diff, relevant tests, hard
|
|
57
|
+
constraints, and remaining work. A completed slice is not the same as a
|
|
58
|
+
completed task.
|
|
59
|
+
|
|
60
|
+
## Plan the next slice
|
|
61
|
+
|
|
62
|
+
For work that spans rounds, submit `round_contract` as a proposal for the next
|
|
63
|
+
slice. Keep `work_item` narrow, bind each item to a configured evidence command
|
|
64
|
+
with `verify_with`, and limit `scope` to files or directories that slice may
|
|
65
|
+
touch. The proposal becomes active only after its declaring round commits.
|
|
66
|
+
While it is open, restating the same proposal continues it; a different
|
|
67
|
+
proposal is ignored as `contract_premature`. If the slice is blocked, report
|
|
68
|
+
`outcome: "blocked"` with a concrete `blocker` instead of silently replacing
|
|
69
|
+
the active contract.
|
|
70
|
+
|
|
71
|
+
This is a planning aid, not a second gate. LoopForge learns the plan only from
|
|
72
|
+
committed evaluation fields, contract proposals, observations, and changes.
|
|
70
73
|
|
|
71
74
|
## Execute a round
|
|
72
75
|
|
|
73
|
-
1. Execute the returned prompt and do
|
|
74
|
-
2. Use the tools and reasoning approach that fit the
|
|
76
|
+
1. Execute the returned prompt and do the repository work.
|
|
77
|
+
2. Use the tools and reasoning approach that fit the slice.
|
|
75
78
|
3. Check actual evidence before claiming success.
|
|
76
|
-
4. Submit one structured
|
|
79
|
+
4. Submit exactly one structured evaluation with `loopforge_next`.
|
|
80
|
+
|
|
81
|
+
After the strict boundary accepts the payload, LoopForge collects before/after
|
|
82
|
+
evidence, runs the **verification gate**, then runs the **enforcement gate**.
|
|
83
|
+
The verification gate checks evaluation consistency, evidence integrity, plan
|
|
84
|
+
and contract conformance, and progress and recovery. The enforcement gate
|
|
85
|
+
turns those findings into one disposition: accept, reject, backtrack, or
|
|
86
|
+
terminate.
|
|
77
87
|
|
|
78
88
|
The four core evaluation fields are strict:
|
|
79
89
|
|
|
80
|
-
| Field |
|
|
90
|
+
| Field | Requirement |
|
|
81
91
|
| --- | --- |
|
|
82
|
-
| `success` | Boolean.
|
|
83
|
-
| `output_summary` | String
|
|
84
|
-
| `constraint_violations` | Array of
|
|
85
|
-
| `should_continue` | Boolean.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
`
|
|
90
|
-
`
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
`
|
|
106
|
-
`
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
no
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
exceptions. They do not turn a valid submission into a transport error. Missing
|
|
119
|
-
or mistyped core fields return `evaluation_invalid` with `details.missing` and
|
|
120
|
-
`details.invalid`. Correct the payload and resubmit the same `roundId`. This
|
|
121
|
-
does not save session state, write a round, enter either gate, increment
|
|
122
|
-
rejection state, or record metrics.
|
|
123
|
-
|
|
124
|
-
Minimal evaluation:
|
|
125
|
-
|
|
126
|
-
```json
|
|
127
|
-
{
|
|
128
|
-
"success": false,
|
|
129
|
-
"output_summary": "Implemented the parser and added 8 passing tests.",
|
|
130
|
-
"constraint_violations": [],
|
|
131
|
-
"should_continue": true,
|
|
132
|
-
"execution_report": {
|
|
133
|
-
"files_changed": ["src/parser.ts", "tests/parser.test.ts"],
|
|
134
|
-
"tests_reported": { "passed": 8, "failed": 0, "skipped": 0 },
|
|
135
|
-
"criterion_claims": [
|
|
136
|
-
{ "criterion_id": "cr-b5a6c7d8", "outcome": "remaining" }
|
|
137
|
-
],
|
|
138
|
-
"contract_item_claims": [
|
|
139
|
-
{ "item_id": "rci-9c8b7a65", "outcome": "met" }
|
|
140
|
-
],
|
|
141
|
-
"progress_estimate": 0.4
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
Everything in `execution_report` is your CLAIM, quoted back for audit — it never
|
|
147
|
-
becomes a verified fact. Only machine observations create facts. Do not put a
|
|
148
|
-
guessed evaluation in free text. The structured object is the authoritative
|
|
149
|
-
submission; `output` is optional supporting context.
|
|
150
|
-
|
|
151
|
-
If a submission warns that its `roundId` no longer matches, the reported round
|
|
152
|
-
already committed. Use the returned held prompt and its `roundId` rather than
|
|
153
|
-
submitting against a later round.
|
|
154
|
-
|
|
155
|
-
## Stable IDs and contracts
|
|
92
|
+
| `success` | Boolean. `true` only when the whole objective and hard constraints are satisfied. |
|
|
93
|
+
| `output_summary` | String describing what changed and what was verified. |
|
|
94
|
+
| `constraint_violations` | Array of real violations, preferably using `c-XXXXXXXX` IDs. |
|
|
95
|
+
| `should_continue` | Boolean. `false` only when the whole task is complete. |
|
|
96
|
+
|
|
97
|
+
Useful optional fields include `execution_report` (`files_changed`,
|
|
98
|
+
`tests_reported`, `criterion_claims`, `contract_item_claims`, and
|
|
99
|
+
`progress_estimate`), `discovered_constraints`, `emerged_subtasks`,
|
|
100
|
+
`subgoal_updates`, `prompt_requests`, `round_contract`, `retroactiveClaims`,
|
|
101
|
+
`gate_ids`, `worker_results`, and objective or constraint revisions.
|
|
102
|
+
|
|
103
|
+
`emerged_subtasks` is the only sub-goal creation channel. It contains plain
|
|
104
|
+
descriptions, never `sg-` IDs. `subgoal_updates` changes existing active IDs;
|
|
105
|
+
done and canceled are terminal and cannot be reopened.
|
|
106
|
+
|
|
107
|
+
`outcome` may be `success`, `partial`, `failed`, or `blocked`. A blocked
|
|
108
|
+
outcome needs a concrete `blocker`; `stop_reason` of `blocked` or
|
|
109
|
+
`needs_human_input` also stops without claiming success.
|
|
110
|
+
|
|
111
|
+
Optional malformed values are normalized or dropped. The strict exceptions are
|
|
112
|
+
`subgoal_updates`, `round_contract`, and
|
|
113
|
+
`execution_report.contract_item_claims`. Shape, reference, duplicate, command,
|
|
114
|
+
and workspace-containment errors return `evaluation_invalid` or
|
|
115
|
+
`contract_invalid` before advance. Correct the payload and resubmit the same
|
|
116
|
+
`roundId`; nothing is committed and no rejection counter moves.
|
|
117
|
+
|
|
118
|
+
Every successful round still needs an `execution_report` with
|
|
119
|
+
`files_changed` and `tests_reported`. `no_change_reason` is an escape only when
|
|
120
|
+
no enabled verification command exists. It never creates evidence and never
|
|
121
|
+
excuses an open contract.
|
|
122
|
+
|
|
123
|
+
Agent reports are claims quoted for audit. They never become verified facts.
|
|
124
|
+
Do not infer a missing field from natural language or put a guessed evaluation
|
|
125
|
+
in free text.
|
|
126
|
+
|
|
127
|
+
## IDs and contracts
|
|
156
128
|
|
|
157
129
|
Prompts render stable IDs beside constraints, criteria, sub-goals, and contract
|
|
158
|
-
items
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
citing its `rci-` ID in `execution_report.contract_item_claims`.
|
|
209
|
-
|
|
210
|
-
A claim never creates a verified fact, and machine evidence can only go stale
|
|
211
|
-
in one direction: the LATEST observation at or after your claim decides, so a
|
|
212
|
-
command that passed early and FAILED in the closing round makes the item
|
|
213
|
-
`contradicted` — a pass cannot outlive a later failure. Claimed-but-unbacked is
|
|
214
|
-
`insufficient`: the round still commits and the debt is surfaced, but once the
|
|
215
|
-
debt persists for `engine.unverified_claim_streak_limit` consecutive rounds
|
|
216
|
-
(default 3) the round is rejected; a repeat of the SAME check rejects again with
|
|
217
|
-
an escalation notice, and the third consecutive same-check rejection terminates
|
|
218
|
-
the loop as `incomplete`.
|
|
219
|
-
|
|
220
|
-
The contract closes when every item is `verified`, or when a round reports
|
|
221
|
-
`outcome: "blocked"` with a `blocker`. While it is open, a DIFFERENT proposal is
|
|
222
|
-
ignored (`contract_premature`) — restate the active contract unchanged to
|
|
223
|
-
continue it. Git changes outside the declared `scope` are scope drift, a machine
|
|
224
|
-
fact no explanation waives: revert the out-of-scope files, or close the contract
|
|
225
|
-
with `outcome: "blocked"` and declare the extended scope in the same submission.
|
|
226
|
-
Repeated drift terminates the loop.
|
|
227
|
-
|
|
228
|
-
Declaration and item claims are a strict structural boundary — `contract_invalid`
|
|
229
|
-
with a same-`roundId` retry and zero state change: a contract with no items, more
|
|
230
|
-
items/scope/refs than the declared limits allow (20 items, 20 `criterion_refs`,
|
|
231
|
-
20 `subgoal_refs` and 20 commands per item, 50 `scope` entries), an item with no
|
|
232
|
-
`verify_with`, an item naming an unknown, disabled, or non-after-capable
|
|
233
|
-
command, a `scope` entry that is not a string or that leaves the workspace, a
|
|
234
|
-
malformed `subgoal_refs` entry, a `subgoal_refs` ID that names no sub-goal of
|
|
235
|
-
this loop (including a sub-goal beyond the 50-entry `emerged_subtasks` intake),
|
|
236
|
-
and a malformed, duplicate, or unknown `contract_item_claims` entry.
|
|
237
|
-
`criterion_claims` are advisory and lenient: an entry with an unknown or
|
|
238
|
-
malformed criterion ID, or an outcome other than `met` / `remaining`, is
|
|
239
|
-
dropped with a warning and never rejects the round.
|
|
240
|
-
|
|
241
|
-
The commands `verify_with` may name are the ones your `loop_policy.json`
|
|
242
|
-
declares under `evidence.commands` and enables there; the runtime runs them
|
|
243
|
-
itself, without a shell, inside the workspace. An item whose bound command
|
|
244
|
-
changed configuration since the contract was declared is `insufficient`, not
|
|
245
|
-
`verified` — the declaration stamps the command configuration it was made
|
|
246
|
-
under.
|
|
247
|
-
|
|
248
|
-
## Backtrack
|
|
249
|
-
|
|
250
|
-
A progress stall can trigger backtrack to the last clean committed round — the
|
|
251
|
-
most recent committed round with no error-level verification flags. The stall
|
|
252
|
-
window is 3 committed rounds (the breaker tier that follows it uses
|
|
253
|
-
`engine.stall_lookback_rounds`, default 3), and the verdict is MACHINE-first:
|
|
254
|
-
when git observations exist for the window, machine motion alone decides it,
|
|
255
|
-
and your `progress_estimate` does not enter — a rising estimate cannot cancel a
|
|
256
|
-
stall, and git motion can only excuse one (it never creates one). Your reported
|
|
257
|
-
estimates are consulted only when the loop has no machine history to read (no
|
|
258
|
-
git provider, or fewer rounds than the window). One machine fact is exempt by
|
|
259
|
-
construction: a round whose success the machine verified is finishing, not
|
|
260
|
-
churning — the closing round of a loop often changes no files at all. So the way
|
|
261
|
-
out of a stall is real, observable work.
|
|
262
|
-
|
|
263
|
-
The backtrack commits a rollback directive that stays out of final history:
|
|
264
|
-
your next submission is the REDO of round `restorePoint + 1` and must reuse the
|
|
265
|
-
round ID the prompt carries; when it commits, the rollback record is replaced
|
|
266
|
-
and disappears from history views.
|
|
267
|
-
|
|
268
|
-
The backtrack prompt opens with a derived **Recovery Brief**:
|
|
269
|
-
|
|
270
|
-
- the trigger rule and the restore point;
|
|
271
|
-
- the redo round's ID (pass it back unchanged to `loopforge_next`);
|
|
272
|
-
- the failed rounds and their approaches — what must NOT be repeated;
|
|
273
|
-
- falsified assumptions — do not rebuild on these;
|
|
274
|
-
- discoveries from the skipped rounds that remain valid;
|
|
275
|
-
- the files to revert and the HEAD the workspace must return to. The prompt
|
|
276
|
-
states these as FACTS and never prescribes a command — the restore is yours
|
|
277
|
-
to perform, by whatever means you judge best.
|
|
278
|
-
|
|
279
|
-
The same brief renders in `.loopforge/state/<loopId>-state.md` under Recent
|
|
280
|
-
while the recovery window is open; it is derived from committed rounds plus
|
|
281
|
-
the in-flight attempt (rejected payloads are never a source) and disappears
|
|
282
|
-
once the redo commits.
|
|
130
|
+
items. Prefer those IDs for `constraint_violations`, criterion claims, status
|
|
131
|
+
updates, and item claims.
|
|
132
|
+
|
|
133
|
+
A sub-goal ID belongs to its declaration event. Re-declaring the same text in a
|
|
134
|
+
later round creates a new sub-goal. Status changes require the exact active
|
|
135
|
+
`sg-` ID; description matching is not a fallback.
|
|
136
|
+
|
|
137
|
+
A Round Contract is a set of evidence-bound items, not prose. Each item must
|
|
138
|
+
bind at least one configured, enabled, after-capable command. The runtime
|
|
139
|
+
derives content-addressed `rc-XXXXXXXX` and `rci-XXXXXXXX` IDs, so restating an
|
|
140
|
+
unchanged proposal keeps its identity. `subgoal_refs` belongs on the item; a
|
|
141
|
+
machine-verified item backs exactly the sub-goals it names, without changing
|
|
142
|
+
their declared `SubGoal.status`.
|
|
143
|
+
|
|
144
|
+
Item status is machine-derived:
|
|
145
|
+
|
|
146
|
+
- `pending`: not claimed as met;
|
|
147
|
+
- `insufficient`: claimed as met but not backed by all required observations;
|
|
148
|
+
- `contradicted`: a bound observation fails, or its entrypoint/configuration is
|
|
149
|
+
no longer trustworthy;
|
|
150
|
+
- `verified`: the Agent claims `met`, every bound command passes in the closing
|
|
151
|
+
round's after phase, and the declaration binding remains intact.
|
|
152
|
+
|
|
153
|
+
The contract closes only when every item is `verified` or a round reports
|
|
154
|
+
`outcome: "blocked"`. Repeated unbacked claims create bounded verification
|
|
155
|
+
debt. The same-check streak escalates at
|
|
156
|
+
`engine.unverified_claim_streak_limit` (default 3) instead of retrying forever.
|
|
157
|
+
|
|
158
|
+
Sub-goals may evolve during execution. LoopForge does not use fuzzy intent or
|
|
159
|
+
similarity to judge drift. The enforced boundary is contract `scope`: work
|
|
160
|
+
outside it is `round_scope_drift`, a machine fact no explanation waives. Revert
|
|
161
|
+
the out-of-scope change, or close the contract as blocked and declare the
|
|
162
|
+
expanded scope in a new proposal.
|
|
163
|
+
|
|
164
|
+
## Backtrack and recovery
|
|
165
|
+
|
|
166
|
+
A progress stall is machine-first when Git history is observable over the
|
|
167
|
+
lookback window. Self-reported `progress_estimate` is only a fallback when
|
|
168
|
+
machine history cannot be read. Machine motion can excuse a stall but cannot
|
|
169
|
+
create one. A machine-backed success round is finishing, even if its closing
|
|
170
|
+
round changes no files.
|
|
171
|
+
|
|
172
|
+
Backtrack records a rollback directive and restores the round counter to the
|
|
173
|
+
last clean committed round. Rejected attempts are never history. The next
|
|
174
|
+
submission is the redo of `restorePoint + 1` and must reuse the prompt's round
|
|
175
|
+
ID. A successful redo retires the rollback record.
|
|
176
|
+
|
|
177
|
+
The Recovery Brief identifies the trigger, restore point, redo ID, failed
|
|
178
|
+
approaches, falsified assumptions, valid discoveries, files to revert, and
|
|
179
|
+
target HEAD. It states restoration facts, not a prescribed command.
|
|
283
180
|
|
|
284
181
|
When backtrack occurs:
|
|
285
182
|
|
|
286
|
-
1. Restore the workspace exactly as requested before doing more work
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
4. Keep valid discoveries from skipped rounds in later evaluations.
|
|
183
|
+
1. Restore the workspace exactly as requested before doing more work.
|
|
184
|
+
2. Read the Recovery Brief, restored prompt, and derived state.
|
|
185
|
+
3. Do not repeat a failed approach without addressing its cause.
|
|
186
|
+
4. Carry valid discoveries into later evaluations.
|
|
291
187
|
|
|
292
|
-
If the
|
|
293
|
-
`
|
|
294
|
-
|
|
295
|
-
When the rolled-back rounds executed under an ACTIVE contract, the redo follows
|
|
296
|
-
the contract path instead of a plain retry: close the stalled contract in the
|
|
297
|
-
redo submission with `outcome: "blocked"` plus a `blocker` explaining why it
|
|
298
|
-
stalled, and declare the REVISED contract in the same submission. Restating the
|
|
299
|
-
stalled contract unchanged keeps it active and commits more of the same, and a
|
|
300
|
-
different proposal while an old contract is still open is ignored as
|
|
301
|
-
`contract_premature`.
|
|
188
|
+
If the rolled-back work used an active contract, close the stalled contract in
|
|
189
|
+
the redo with `outcome: "blocked"` and declare the revised contract in that
|
|
190
|
+
same submission. Restating the stalled contract commits more of the same.
|
|
302
191
|
|
|
303
192
|
## Interpret results
|
|
304
193
|
|
|
305
|
-
- `prompt
|
|
306
|
-
- `enforcementAction: "reject"`:
|
|
307
|
-
|
|
194
|
+
- Non-null `prompt`: execute it and submit the next evaluation.
|
|
195
|
+
- `enforcementAction: "reject"`: retry the same logical round and ID; the
|
|
196
|
+
attempt increases.
|
|
308
197
|
- `enforcementAction: "backtrack"`: restore the workspace, then continue from
|
|
309
198
|
the restored prompt and round.
|
|
310
|
-
- `prompt
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
`
|
|
314
|
-
`insufficient`
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
`
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
already exists in this process — inspect or resume it instead of starting a
|
|
330
|
-
duplicate.
|
|
331
|
-
|
|
332
|
-
`completed` means the machine verified the completion: success plus every
|
|
333
|
-
contract item `verified`, or no active contract. An explicit `outcome:
|
|
334
|
-
"blocked"` (or `stop_reason: "blocked"` / `"needs_human_input"`) always stops as
|
|
335
|
-
`blocked`, never as `completed`. `incomplete` means you stopped while the
|
|
336
|
-
machine could not verify completion — claims the bound commands did not back;
|
|
337
|
-
contract verification debt that persisted past
|
|
338
|
-
`engine.unverified_claim_streak_limit` also ends here rather than accepting
|
|
339
|
-
another unverified round. `failed` means the Agent gave up. `max_rounds` is the
|
|
340
|
-
safety limit. `stalled` means the runtime could not produce the next round's
|
|
341
|
-
prompt. `enforcement_terminated` means repeated integrity failures reached a
|
|
342
|
-
terminal ladder. `paused` means the durable session remains available for
|
|
343
|
-
resume, and `cancelled` that the session was deleted.
|
|
199
|
+
- Null `prompt`: inspect `stopReason`.
|
|
200
|
+
|
|
201
|
+
Read `verificationStatus`, `roundSuccess`, `level`, `warnings`, and
|
|
202
|
+
`enforcementReason` before planning the next slice. `trusted` means claimed
|
|
203
|
+
work is machine-backed, `insufficient` means evidence is missing, and
|
|
204
|
+
`contradicted` means a machine fact denies a claim. These are evidence
|
|
205
|
+
postures, not subjective quality scores.
|
|
206
|
+
|
|
207
|
+
Errors use `{ok: false, error: {code, message, retryable, ...}}`. Branch on the
|
|
208
|
+
stable `code`, not the prose in `message`. Payload errors such as
|
|
209
|
+
`evaluation_invalid`, `contract_invalid`, `policy_invalid`, and round-ID
|
|
210
|
+
errors are retryable with the same ID. `session_not_found`, `state_unavailable`,
|
|
211
|
+
and `gate_disabled` describe state or policy; do not blindly resubmit.
|
|
212
|
+
|
|
213
|
+
`completed` means success plus every active contract item is `verified`, or
|
|
214
|
+
there is no active contract. Explicit `blocked` always wins over success.
|
|
215
|
+
`incomplete` means completion was not machine-verified. Other terminal reasons
|
|
216
|
+
include `failed`, `max_rounds`, `stalled`, `enforcement_terminated`, `paused`,
|
|
217
|
+
and `cancelled`.
|
|
344
218
|
|
|
345
219
|
## Prompt levels and views
|
|
346
220
|
|
|
347
|
-
L0 is a lean same-round retry, L1
|
|
348
|
-
rehydration. They control state density only
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
loop
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
Replay answers what happened; Audit checks whether facts and claims are
|
|
366
|
-
supported; Explain shows why a round was decided the way it was.
|
|
367
|
-
|
|
368
|
-
The optional `.loopforge/state/<loopId>-state.md` file is derived and can be
|
|
369
|
-
regenerated. In L2 the prompt may omit the full markdown state and point at
|
|
370
|
-
that file instead (pointer mode), so read it when the prompt says so — but it
|
|
371
|
-
is a derived view, never an independent source of truth.
|
|
372
|
-
|
|
373
|
-
## Control and delegation
|
|
374
|
-
|
|
375
|
-
Use `loopforge_pause` before an intentional interruption,
|
|
221
|
+
L0 is a lean same-round retry, L1 normal continuation, and L2 full
|
|
222
|
+
rehydration. They control state density only, never a reasoning technique. L2
|
|
223
|
+
comes from round facts such as the first round, a plan or checkpoint boundary,
|
|
224
|
+
recovery, contradiction, or repeated rejection. It is not a round-count timer.
|
|
225
|
+
|
|
226
|
+
Use `loopforge_status` with `view: "session"` for the live round,
|
|
227
|
+
`view: "loop"` for committed health, `view: "all"` after a restart,
|
|
228
|
+
`view: "audit"` for completeness and evidence, and `view: "explain"` for a
|
|
229
|
+
round's active contract, observations, flags, and decision. Use
|
|
230
|
+
`loopforge_replay` for the committed timeline and diffs.
|
|
231
|
+
|
|
232
|
+
The optional `.loopforge/state/<loopId>-state.md` is derived and regenerable.
|
|
233
|
+
Read it when an L2 prompt points to it, but never treat it as a second source
|
|
234
|
+
of truth.
|
|
235
|
+
|
|
236
|
+
## Gates and delegation
|
|
237
|
+
|
|
238
|
+
Use `loopforge_pause` for an intentional interruption,
|
|
376
239
|
`loopforge_resume` to reconstruct a durable session, and `loopforge_stop` only
|
|
377
240
|
for an intentional terminal stop.
|
|
378
241
|
|
|
379
|
-
The two gate tools are opt-in
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
Classification is conservative: anything not provably safe is `user_required`,
|
|
393
|
-
which returns a gate id and an approval question. Present that question to the
|
|
394
|
-
human, record their decision with `loopforge_gate_resolve`, and cite the
|
|
395
|
-
approved gate id via `evaluation.gate_ids` in the round that performs the
|
|
396
|
-
action — an unapproved or unknown cited gate rejects the round. Safe
|
|
397
|
-
preparation work (investigation, dry-runs, rollback evidence) never needs a
|
|
398
|
-
gate. Remember: approval is recorded through you, the Agent — LoopForge cannot
|
|
399
|
-
machine-verify a human is present.
|
|
400
|
-
|
|
401
|
-
Delegation does not create a separate LoopForge mode. Give each worker a
|
|
402
|
-
self-contained subtask and relevant hard constraints, then place its result in
|
|
403
|
-
`worker_results` so discoveries can enter the next Canonical State.
|
|
242
|
+
The two gate tools are opt-in through `policy.gate.enabled`. When enabled,
|
|
243
|
+
`loopforge_gate_check` preflights a structured action with its description,
|
|
244
|
+
scope, effects, reversibility, and authorization. Classification is
|
|
245
|
+
conservative: anything not provably safe becomes `user_required`. Present the
|
|
246
|
+
approval question, record the decision with `loopforge_gate_resolve`, and cite
|
|
247
|
+
the approved gate ID in `evaluation.gate_ids`. LoopForge records the process,
|
|
248
|
+
but cannot prove that a human was present because the Agent submits the resolve
|
|
249
|
+
call. Safe investigation and dry-runs need no gate.
|
|
250
|
+
|
|
251
|
+
Delegation does not create another LoopForge mode. Give each worker a
|
|
252
|
+
self-contained subtask and hard constraints, then place the result in
|
|
253
|
+
`worker_results` so it can enter the next Canonical State.
|
|
404
254
|
|
|
405
255
|
## Rules
|
|
406
256
|
|
|
407
257
|
1. Execute the prompt instead of generating another prompt.
|
|
408
258
|
2. Submit one honest structured evaluation after each attempt.
|
|
409
|
-
3.
|
|
410
|
-
4.
|
|
259
|
+
3. Treat required command evidence and verification findings as authoritative.
|
|
260
|
+
4. Restore the workspace before working after backtrack.
|
|
411
261
|
5. Keep one loop focused on one user objective.
|
|
412
262
|
6. Do not advance a paused or stopped session through another process.
|
|
413
|
-
7. Continue
|
|
414
|
-
|
|
263
|
+
7. Continue in the same Agent task when possible. LoopForge preserves state but
|
|
264
|
+
does not create a background Agent.
|