@cassiomc1/forgeloop 0.1.12 → 0.1.14
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/.cursor/rules/project-loop.mdc +1 -1
- package/.github/copilot-instructions.md +1 -1
- package/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/LOOP_ENGINEERING.md +73 -0
- package/LOOP_SYSTEM_DESIGN.md +9 -7
- package/PROTOCOL_INTEGRATION.md +99 -0
- package/README.md +41 -41
- package/THREAT_MODEL.md +6 -0
- package/package.json +1 -1
- package/schemas/authority.schema.json +34 -0
- package/src/commands/inspect.js +2 -0
- package/src/commands/prepare-completion.js +2 -2
- package/src/commands/validate-protocol.js +11 -8
- package/src/core/audit.js +2 -2
- package/src/core/checks.js +12 -5
- package/src/core/completion-artifacts.js +122 -23
- package/src/core/completion-recovery.js +4 -0
- package/src/core/completion-relationships.js +39 -4
- package/src/core/completion.js +29 -7
- package/src/core/conformance.js +47 -5
- package/src/core/coverage.js +15 -2
- package/src/core/evidence-readiness.js +32 -6
- package/src/core/inspect.js +3 -1
- package/src/core/native-adapters.js +4 -0
- package/src/core/next-action.js +87 -9
- package/src/core/phase.js +29 -6
- package/src/core/protocol.js +5 -0
- package/src/core/receipt.js +6 -6
- package/src/core/runtime-context.js +80 -0
- package/src/core/trusted-authority.js +296 -0
- package/src/core/verification-capability.js +546 -0
|
@@ -16,7 +16,7 @@ Do not treat ForgeLoop as vendor-specific, optional, or to follow only "in spiri
|
|
|
16
16
|
4. Respect higher-level and local instructions and the latest request.
|
|
17
17
|
5. Make the minimum change, run specific checks, and run proportional regression checks.
|
|
18
18
|
6. Diagnose failures before fixing them; do not repeat attempts without new evidence.
|
|
19
|
-
7. Request authority for unrelated actions, installations, and publications. For missing Qwen-MM-Plugins, follow `LOOP_ENGINEERING.md`.
|
|
19
|
+
7. Request authority for unrelated actions, installations, and publications. Do not install a missing verification tool merely to satisfy a check. For missing Qwen-MM-Plugins, follow `LOOP_ENGINEERING.md`.
|
|
20
20
|
8. After implementation begins, do not return a final result in `EXECUTING`: advance through `VERIFYING` → structured evidence → `REVIEWING` → execution receipt → validator-backed `COMPLETE`. If closure cannot be reached, report `BLOCKED` or `PARTIALLY VERIFIED`.
|
|
21
21
|
|
|
22
22
|
After implementation work for the current task is complete, run `forgeloop next` before returning a final result. Follow the returned lifecycle action until ForgeLoop reaches a terminal state or an explicit blocker.
|
|
@@ -13,7 +13,7 @@ Use these instructions across the repository while preserving local rules.
|
|
|
13
13
|
- Respect the latest request, scope, and higher-level instructions.
|
|
14
14
|
- Make the smallest coherent change; validate with specific and regression checks.
|
|
15
15
|
- Diagnose causes before fixing failures; do not make unverified attempts.
|
|
16
|
-
- Do not install software, publish, delete, or alter external state without authority. For missing Qwen-MM-Plugins, follow `LOOP_ENGINEERING.md`.
|
|
16
|
+
- Do not install software, publish, delete, or alter external state without authority. Do not install a missing verification tool merely to satisfy a check. For missing Qwen-MM-Plugins, follow `LOOP_ENGINEERING.md`.
|
|
17
17
|
- After implementation begins, do not return a final result in `EXECUTING`: advance through `VERIFYING` → structured evidence → `REVIEWING` → execution receipt → validator-backed `COMPLETE`. If closure cannot be reached, report `BLOCKED` or `PARTIALLY VERIFIED`.
|
|
18
18
|
|
|
19
19
|
After implementation work for the current task is complete, run `forgeloop next` before returning a final result. Follow the returned lifecycle action until ForgeLoop reaches a terminal state or an explicit blocker.
|
package/AGENTS.md
CHANGED
|
@@ -11,7 +11,7 @@ Do not treat ForgeLoop as vendor-specific, optional, or to follow only "in spiri
|
|
|
11
11
|
1. Use [`GUIDE_ROUTER.md`](./GUIDE_ROUTER.md) to select relevant guides and report activated guide IDs.
|
|
12
12
|
1. Make the smallest coherent change, run specific checks, and proportional regression checks.
|
|
13
13
|
1. Diagnose failures before fixing; do not repeat attempts without new evidence.
|
|
14
|
-
1. Do not install software, publish, delete, or migrate data without authority. For missing Qwen-MM-Plugins, follow `LOOP_ENGINEERING.md`.
|
|
14
|
+
1. Do not install software, publish, delete, or migrate data without authority. Do not install a missing verification tool merely to satisfy a check. For missing Qwen-MM-Plugins, follow `LOOP_ENGINEERING.md`.
|
|
15
15
|
1. Before implementation, create/validate `.forgeloop/current-contract.json`, persist routing, satisfy gates, and require `forgeloop preflight` to return `READY`.
|
|
16
16
|
1. Before claiming `COMPLETE`, require `forgeloop complete` to return `VALID`; otherwise report completion as not protocol-verified.
|
|
17
17
|
1. After implementation begins, do not return a final result in `EXECUTING`: advance through `VERIFYING` → structured evidence → `REVIEWING` → execution receipt → validator-backed `COMPLETE`. If closure cannot be reached, report `BLOCKED` or `PARTIALLY VERIFIED`.
|
package/CLAUDE.md
CHANGED
|
@@ -13,7 +13,7 @@ When working in this repository:
|
|
|
13
13
|
1. Consult [`GUIDE_ROUTER.md`](./GUIDE_ROUTER.md), select relevant guides, and announce their IDs.
|
|
14
14
|
1. Make small changes, run specific checks, and run proportional regression checks.
|
|
15
15
|
1. Investigate root causes before fixing failures; do not make unverified attempts.
|
|
16
|
-
1. Request authority for unrelated installations, publications, deletions, or migrations. For missing Qwen-MM-Plugins, follow `LOOP_ENGINEERING.md`.
|
|
16
|
+
1. Request authority for unrelated installations, publications, deletions, or migrations. Do not install a missing verification tool merely to satisfy a check. For missing Qwen-MM-Plugins, follow `LOOP_ENGINEERING.md`.
|
|
17
17
|
1. After implementation begins, do not return a final result in `EXECUTING`: advance through `VERIFYING` → structured evidence → `REVIEWING` → execution receipt → validator-backed `COMPLETE`. If closure cannot be reached, report `BLOCKED` or `PARTIALLY VERIFIED`.
|
|
18
18
|
1. After implementation work for the current task is complete, run `forgeloop next` before returning a final result. Follow the returned lifecycle action until ForgeLoop reaches a terminal state or an explicit blocker.
|
|
19
19
|
1. Report current evidence, limitations, and publication state without claiming checks that were not run.
|
package/LOOP_ENGINEERING.md
CHANGED
|
@@ -68,6 +68,79 @@ If the required CLI/API capability cannot be resolved:
|
|
|
68
68
|
Report the corresponding ForgeLoop dimension as `NOT_VERIFIED` with
|
|
69
69
|
`E_FORGELOOP_CLI_UNAVAILABLE`.
|
|
70
70
|
|
|
71
|
+
### Missing verification tool policy
|
|
72
|
+
|
|
73
|
+
A missing verification tool does not grant authority to install it.
|
|
74
|
+
|
|
75
|
+
When a verification command or checker is unavailable:
|
|
76
|
+
|
|
77
|
+
1. Try only already-installed or explicitly non-installing resolution paths.
|
|
78
|
+
2. Prefer an already available equivalent when it can verify the same requirement.
|
|
79
|
+
3. If no suitable local capability exists, request explicit installation authority
|
|
80
|
+
only when the missing verification is genuinely required.
|
|
81
|
+
4. If authority is unavailable or the check is non-critical, record the affected
|
|
82
|
+
verification dimension as `NOT_VERIFIED` with `E_VERIFICATION_TOOL_UNAVAILABLE`.
|
|
83
|
+
|
|
84
|
+
Do not retry a failed non-installing lookup with a command that implicitly
|
|
85
|
+
downloads or installs the missing package.
|
|
86
|
+
|
|
87
|
+
Examples of forbidden escalation without authority:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
npx --no-install TOOL → missing
|
|
91
|
+
npx TOOL → implicit install
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
command -v TOOL → missing
|
|
96
|
+
package-manager install TOOL
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
local executable missing
|
|
101
|
+
curl | sh
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Automatic installation is allowed only when an explicit ForgeLoop rule grants
|
|
105
|
+
that exact task-scoped installation authority and higher-priority platform/user
|
|
106
|
+
rules permit it.
|
|
107
|
+
|
|
108
|
+
A missing checker must never be converted into environmental mutation merely
|
|
109
|
+
to make verification pass.
|
|
110
|
+
|
|
111
|
+
### Verification command resolution modes and validator enforcement
|
|
112
|
+
|
|
113
|
+
Every verification command path is classified by resolution mode:
|
|
114
|
+
|
|
115
|
+
| Mode | Examples | May install software | Authority required |
|
|
116
|
+
| --- | --- | --- | --- |
|
|
117
|
+
| `LOCAL_EXECUTABLE` | `node scripts/test.js`, `python3 -m unittest`, `./bin/check` | No | No |
|
|
118
|
+
| `LOCAL_PACKAGE_BINARY` | `./node_modules/.bin/tool`, `npm test`, `pnpm test`, `yarn test` | No | No |
|
|
119
|
+
| `NON_INSTALLING_RESOLUTION` | `npx --no-install tool`, `npx --no tool` | No | No |
|
|
120
|
+
| `INSTALL_CAPABLE_RESOLUTION` | `npx tool`, `pnpm dlx tool`, `yarn dlx tool`, `bunx tool`, `uvx tool`, `pipx run tool` | Yes | Yes (`E_INSTALLATION_AUTHORITY_REQUIRED`) |
|
|
121
|
+
| `EXPLICIT_INSTALLATION` | `npm install tool`, `pnpm add tool`, `pip install tool`, `cargo install tool` | Yes | Yes (`E_INSTALLATION_AUTHORITY_REQUIRED`) |
|
|
122
|
+
|
|
123
|
+
**Validator-enforced rule**: Any verification command executed via an installation-capable or explicit-installation resolution mode without a valid canonical installation authority grant is rejected by `record-check`, `audit`, and `complete` with error code `E_INSTALLATION_AUTHORITY_REQUIRED`, `E_AUTHORITY_INVALID`, `E_AUTHORITY_SCOPE_MISMATCH`, or `E_AUTHORITY_UNTRUSTED_SOURCE` and cannot contribute to `VALID` completion.
|
|
124
|
+
|
|
125
|
+
Authority cannot be self-issued by the actor consuming it. Boolean fields inside verification evidence (such as `installationAuthorized: true`) are not sufficient proof of installation authority. Installation authority must be established via a canonical authority grant supplied by a host/operator trust boundary and referenced via `installationAuthorityRef`.
|
|
126
|
+
|
|
127
|
+
The runtime authority context has two modes:
|
|
128
|
+
|
|
129
|
+
- `NONE` is the default for the actor-facing standalone CLI. `FORGELOOP_AUTHORITY_FILE` and `FORGELOOP_AUTHORITY_DIR` may select candidate source metadata for compatibility and diagnostics, but they do not make a source trusted. An environment-selected source is rejected with `E_AUTHORITY_UNTRUSTED_SOURCE` when it is used for an installation-capable verification.
|
|
130
|
+
- `HOST_ATTESTED` is an internal integration context supplied by a host-owned wrapper, embedded API, or equivalent boundary. It may select a trusted authority file, directory, or in-memory provider only when the actor cannot replace that context at command invocation time. The CLI exposes no flag that promotes a source to `HOST_ATTESTED`.
|
|
131
|
+
|
|
132
|
+
External path is not equivalent to external authority ownership. The host-attested source must still resolve outside the actor-writable target, and a project-local `.forgeloop/authorities/` artifact remains an untrusted reference, cache, diagnostic, or mirror by default. A local claim such as `source: operator` is not proof of operator authority.
|
|
133
|
+
|
|
134
|
+
ForgeLoop validates authority semantics, while the host defines the trust boundary. If the host grants the actor write access to the configured attested source, the host boundary is compromised and ForgeLoop cannot distinguish operator authority from actor fabrication without a stronger external trust anchor.
|
|
135
|
+
|
|
136
|
+
### Stale receipt recovery invariant
|
|
137
|
+
|
|
138
|
+
Every recovery action returned by `forgeloop next` must be executable from the state that produced it. When work state changes legitimately after preparing a completion receipt, `forgeloop prepare-completion` refreshes the receipt and re-binds it to current state and changed paths without requiring manual deletion of `.forgeloop/execution-receipt.json`.
|
|
139
|
+
|
|
140
|
+
### Conformance profile escalation policy
|
|
141
|
+
|
|
142
|
+
A run started in Standard conformance must not be silently escalated to Strict after validator-backed completion. Strict validation is a separate conformance profile. If Strict revalidation is performed after Standard `COMPLETE`, it is treated as a distinct revalidation cycle and does not retroactively invalidate a valid Standard result.
|
|
143
|
+
|
|
71
144
|
## Blocking vs Non-Blocking Decisions
|
|
72
145
|
|
|
73
146
|
Classify every unresolved decision before deciding whether to ask the user.
|
package/LOOP_SYSTEM_DESIGN.md
CHANGED
|
@@ -10,11 +10,13 @@ The system should use every guide that materially helps the task without loading
|
|
|
10
10
|
|
|
11
11
|
## Primary decisions
|
|
12
12
|
|
|
13
|
-
- The
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
- The protocol is vendor-neutral, project-scoped, and capability-based,
|
|
14
|
+
supporting any AI agent, coding assistant, IDE runtime, or developer workflow.
|
|
15
|
+
- Common discovery surfaces (e.g. `AGENTS.md`, `CLAUDE.md`, `.cursor/rules/`,
|
|
16
|
+
`.github/copilot-instructions.md`) use project-local shims delegating to the
|
|
17
|
+
canonical protocol under `.forgeloop/kit/`, while other environments use the
|
|
18
|
+
shared `AGENTS.md` entry point or manual bootstrap.
|
|
19
|
+
- The portable instruction layer uses Markdown and each environment's native instruction mechanism; the optional local Node CLI validates and installs the kit without an agent runtime or third-party dependency.
|
|
18
20
|
- English is the only language used by repository content and guide metadata.
|
|
19
21
|
- The agent uses all applicable guides, not every file indiscriminately.
|
|
20
22
|
- Design, planning, test-first, and review process gates live in the canonical loop and scale with task risk instead of becoming unconditional boilerplate in every adapter or architecture note.
|
|
@@ -389,8 +391,8 @@ update practice.
|
|
|
389
391
|
## Acceptance criteria
|
|
390
392
|
|
|
391
393
|
- The repository and its maintained content are English-only.
|
|
392
|
-
-
|
|
393
|
-
|
|
394
|
+
- Common project instruction surfaces and generic bootstrap mechanisms have a
|
|
395
|
+
documented entry into one canonical loop.
|
|
394
396
|
- The router selects every relevant guide and excludes irrelevant guides in the six defined scenarios.
|
|
395
397
|
- The profile contains verifiable facts, sources, and real commands without secrets.
|
|
396
398
|
- The loop requires evidence before completion claims and exits safely when blocked.
|
package/PROTOCOL_INTEGRATION.md
CHANGED
|
@@ -140,6 +140,92 @@ If the required CLI or API capability cannot be resolved:
|
|
|
140
140
|
|
|
141
141
|
Report the corresponding ForgeLoop dimension as `NOT_VERIFIED` / `E_FORGELOOP_CLI_UNAVAILABLE`.
|
|
142
142
|
|
|
143
|
+
## Missing tool capability
|
|
144
|
+
|
|
145
|
+
A missing tool is a capability gap, not installation authority.
|
|
146
|
+
|
|
147
|
+
If an expected verifier, browser tool, linter, analyzer, or test dependency is
|
|
148
|
+
not already available:
|
|
149
|
+
|
|
150
|
+
- use a suitable existing local equivalent when possible;
|
|
151
|
+
- otherwise request authority if installation is necessary and allowed;
|
|
152
|
+
- otherwise report the affected verification dimension as not verified with
|
|
153
|
+
`E_VERIFICATION_TOOL_UNAVAILABLE`.
|
|
154
|
+
|
|
155
|
+
Every verification command is classified by resolution mode (`LOCAL_EXECUTABLE`,
|
|
156
|
+
`LOCAL_PACKAGE_BINARY`, `NON_INSTALLING_RESOLUTION`, `INSTALL_CAPABLE_RESOLUTION`,
|
|
157
|
+
`EXPLICIT_INSTALLATION`). Any command that uses an install-capable or installation
|
|
158
|
+
path without a valid canonical authority reference is rejected by `record-check`,
|
|
159
|
+
`audit`, and `complete` with `E_INSTALLATION_AUTHORITY_REQUIRED`, `E_AUTHORITY_INVALID`,
|
|
160
|
+
`E_AUTHORITY_SCOPE_MISMATCH`, or `E_AUTHORITY_UNTRUSTED_SOURCE`.
|
|
161
|
+
|
|
162
|
+
```text
|
|
163
|
+
capability ≠ authority
|
|
164
|
+
evidence ≠ authority grant
|
|
165
|
+
actor claim ≠ operator grant
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Authority cannot be self-issued by the actor consuming it. Boolean fields inside
|
|
169
|
+
verification evidence are not sufficient proof of installation authority.
|
|
170
|
+
|
|
171
|
+
### Authority provenance
|
|
172
|
+
|
|
173
|
+
Authority provenance is external to actor-authored project state. An external
|
|
174
|
+
path is not equivalent to external authority ownership:
|
|
175
|
+
|
|
176
|
+
```text
|
|
177
|
+
outside target
|
|
178
|
+
≠
|
|
179
|
+
outside actor control
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The standalone CLI uses `trustMode: NONE`. `FORGELOOP_AUTHORITY_FILE` and
|
|
183
|
+
`FORGELOOP_AUTHORITY_DIR` select candidate authority sources, but they do not
|
|
184
|
+
make a source trusted in actor-facing execution. Environment-selected sources
|
|
185
|
+
are rejected with `E_AUTHORITY_UNTRUSTED_SOURCE` for install-capable checks.
|
|
186
|
+
|
|
187
|
+
Trusted authority requires an explicit `HOST_ATTESTED` runtime context supplied
|
|
188
|
+
through an integration boundary the active actor cannot replace at command
|
|
189
|
+
invocation time. Configuration is not trust:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
environment-selected source
|
|
193
|
+
≠
|
|
194
|
+
host-attested source
|
|
195
|
+
|
|
196
|
+
configuration
|
|
197
|
+
≠
|
|
198
|
+
trust
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The host-attested source must still resolve outside the actor-writable target. A
|
|
202
|
+
project-local authority reference may identify a grant, but it does not create
|
|
203
|
+
the root of trust.
|
|
204
|
+
|
|
205
|
+
```text
|
|
206
|
+
actor-authored evidence
|
|
207
|
+
≠
|
|
208
|
+
trusted authority
|
|
209
|
+
|
|
210
|
+
project-local file
|
|
211
|
+
≠
|
|
212
|
+
host grant
|
|
213
|
+
|
|
214
|
+
declared provenance
|
|
215
|
+
≠
|
|
216
|
+
verified provenance
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
A local artifact claiming `source: operator` is not sufficient proof of operator
|
|
220
|
+
authority. The actor-facing CLI must not expose an equivalent of
|
|
221
|
+
`--authority-source-attested-by-host` or `--trusted-authority-file` that
|
|
222
|
+
self-promotes a source. If the host exposes the attested source as writable to
|
|
223
|
+
the actor, the host boundary has been compromised and ForgeLoop cannot provide
|
|
224
|
+
cryptographic attestation by itself.
|
|
225
|
+
|
|
226
|
+
Never convert `PROTOCOL_LIMITED` into environmental mutation by implicitly
|
|
227
|
+
installing a package.
|
|
228
|
+
|
|
143
229
|
## Optional capability extensions
|
|
144
230
|
|
|
145
231
|
The installed loop directs the active actor to inspect native model and harness
|
|
@@ -150,6 +236,19 @@ through native mechanisms or upstream installers, then verify it before use.
|
|
|
150
236
|
API credentials, system packages, and unrelated environment changes remain
|
|
151
237
|
separately gated.
|
|
152
238
|
|
|
239
|
+
## Delegation scope
|
|
240
|
+
|
|
241
|
+
Delegation is optional.
|
|
242
|
+
|
|
243
|
+
A run that contains no delegation events, no delegated task references, and no
|
|
244
|
+
delegation artifacts is a valid single-actor run.
|
|
245
|
+
|
|
246
|
+
Missing delegation artifacts must not make such a run incomplete. For a purely
|
|
247
|
+
local single-actor lifecycle, the delegation dimension is `NOT_APPLICABLE`.
|
|
248
|
+
|
|
249
|
+
Once delegation is observed in canonical state, receipt, or event history, the
|
|
250
|
+
required delegation artifacts become mandatory.
|
|
251
|
+
|
|
153
252
|
## Instruction precedence
|
|
154
253
|
|
|
155
254
|
When multiple instruction layers exist, follow standard precedence:
|
package/README.md
CHANGED
|
@@ -1,26 +1,18 @@
|
|
|
1
|
-
# ForgeLoop —
|
|
1
|
+
# ForgeLoop — Verifiable Engineering Protocol
|
|
2
2
|
|
|
3
3
|
[](https://github.com/cassiomc1/forgeloop/actions/workflows/docs-quality.yml)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
It covers product strategy, code, testing, security, performance,
|
|
7
|
-
accessibility, design, and web games across web, mobile, and desktop projects.
|
|
5
|
+
ForgeLoop is a portable, verifiable engineering protocol for AI-assisted development and developer workflows.
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
`AGENTS.md`, `CLAUDE.md`, `.cursor/rules`, and
|
|
11
|
-
`.github/copilot-instructions.md`. The integration contract and capability levels are documented
|
|
12
|
-
in [`PROTOCOL_INTEGRATION.md`](./PROTOCOL_INTEGRATION.md). Adopt only the guides
|
|
13
|
-
relevant to the target project.
|
|
7
|
+
It is project-scoped, capability-based, and vendor-neutral. It turns intent into contract-driven execution with deterministic routing, resumable state, evidence-backed verification, recovery, and validator-backed completion.
|
|
14
8
|
|
|
15
|
-
ForgeLoop
|
|
16
|
-
and developer workflows. It turns intent into contract-driven execution with
|
|
17
|
-
deterministic routing, resumable state, evidence-backed verification, recovery, and
|
|
18
|
-
validator-backed completion.
|
|
9
|
+
ForgeLoop does not depend on a specific model, provider, agent product, IDE, or orchestration runtime.
|
|
19
10
|
|
|
20
|
-
The
|
|
21
|
-
|
|
22
|
-
discovery
|
|
23
|
-
|
|
11
|
+
The repository also provides an English-only collection of operational engineering guides covering product strategy, clean code, testing, security, performance, accessibility, visual design, and web games across web, mobile, and desktop projects.
|
|
12
|
+
|
|
13
|
+
Project-local discovery surfaces (`AGENTS.md`, `CLAUDE.md`, `.cursor/rules/project-loop.mdc`, `.github/copilot-instructions.md`) and manual bootstrap paths delegate to the same canonical protocol in `.forgeloop/kit/`. The capability levels and integration contract are documented in [`PROTOCOL_INTEGRATION.md`](./PROTOCOL_INTEGRATION.md). Adopt only the guides relevant to the target project.
|
|
14
|
+
|
|
15
|
+
The npm package also ships the local `forgeloop` CLI. In a target project it installs canonical documents under `.forgeloop/kit/`, keeps only small native discovery shims at the root, and stores mutable protocol artifacts under `.forgeloop/`.
|
|
24
16
|
|
|
25
17
|
## Catalog
|
|
26
18
|
|
|
@@ -88,13 +80,13 @@ Request → discovery → profile → routing → plan → execution
|
|
|
88
80
|
└ evidence-only rejection / next cycle
|
|
89
81
|
```
|
|
90
82
|
|
|
91
|
-
ForgeLoop is project-scoped, capability-based, and vendor-neutral.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
capability levels, degradation rules, and precedence
|
|
83
|
+
ForgeLoop is project-scoped, capability-based, and vendor-neutral.
|
|
84
|
+
|
|
85
|
+
Project-local discovery surfaces delegate to the same canonical ForgeLoop protocol. Execution environments that automatically discover one of those instruction surfaces can use it directly, while custom runtimes, automation systems, and developer workflows can use the manual bootstrap path.
|
|
86
|
+
|
|
87
|
+
Capabilities determine execution. Runtime names do not determine protocol applicability.
|
|
88
|
+
|
|
89
|
+
See [`PROTOCOL_INTEGRATION.md`](./PROTOCOL_INTEGRATION.md) for discovery, capability levels, degradation rules, and precedence.
|
|
98
90
|
|
|
99
91
|
### Migration recovery and release freeze
|
|
100
92
|
|
|
@@ -117,12 +109,12 @@ The regression suite injects failures at these boundaries and verifies that
|
|
|
117
109
|
owned cleanup. The frozen published installation under
|
|
118
110
|
[`tests/fixtures/legacy-0.1.6/`](./tests/fixtures/legacy-0.1.6/) is derived
|
|
119
111
|
from the real npm tarball, includes provenance and digests, and is copied into
|
|
120
|
-
The
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
112
|
+
The latest verified published npm release is `@cassiomc1/forgeloop@0.1.14`.
|
|
113
|
+
The repository release is `0.1.14`.
|
|
114
|
+
Earlier `0.1.8`, `0.1.9`, `0.1.10`, `0.1.11`, `0.1.12`, and `0.1.13` references are historical; never move
|
|
115
|
+
their tags or `v0.1.10`. Release `0.1.14` enforces verification installation
|
|
116
|
+
authority, provides recoverable stale receipt lifecycle in `prepare-completion`,
|
|
117
|
+
and validates single-actor protocol runs.
|
|
126
118
|
|
|
127
119
|
## How to prompt ForgeLoop
|
|
128
120
|
|
|
@@ -212,12 +204,13 @@ project without overwriting local instructions. When the package is available
|
|
|
212
204
|
in the npm registry, use the commands below; otherwise use the repository
|
|
213
205
|
checkout fallback.
|
|
214
206
|
|
|
215
|
-
The current
|
|
216
|
-
|
|
217
|
-
|
|
207
|
+
The current repository package is `@cassiomc1/forgeloop@0.1.14`.
|
|
208
|
+
The latest verified published npm release is `@cassiomc1/forgeloop@0.1.14`.
|
|
209
|
+
For reproducible published-package runs or release-identity checks,
|
|
210
|
+
pin the published version:
|
|
218
211
|
|
|
219
212
|
```bash
|
|
220
|
-
npx @cassiomc1/forgeloop@0.1.
|
|
213
|
+
npx @cassiomc1/forgeloop@0.1.14 --version
|
|
221
214
|
npx @cassiomc1/forgeloop init
|
|
222
215
|
npx @cassiomc1/forgeloop doctor
|
|
223
216
|
npx @cassiomc1/forgeloop update
|
|
@@ -314,11 +307,13 @@ cross-artifact relationships plus the same derived freshness classification
|
|
|
314
307
|
used by `inspect` and `status`. Supply `--contract-file` to compare the saved
|
|
315
308
|
contract fingerprint with the current contract; omitting it leaves contract
|
|
316
309
|
freshness as `NOT_VERIFIED` and a complete artifact set requires revalidation.
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
`
|
|
321
|
-
|
|
310
|
+
Delegation artifacts are required only when delegation is present in the
|
|
311
|
+
canonical execution history or explicitly supplied as part of a delegated run.
|
|
312
|
+
For a purely local single-actor lifecycle, the delegation dimension is
|
|
313
|
+
`NOT_APPLICABLE` and does not require task briefs or delegated results. When
|
|
314
|
+
delegation is in scope, also supply the matching repeated
|
|
315
|
+
`--task-brief <path>` and `--delegated-result <path>` inputs; omitting them in a
|
|
316
|
+
delegated run reports `INCOMPLETE`.
|
|
322
317
|
It returns `VALID`, `INCOMPLETE`, `STALE`, `INCONSISTENT`, or `INVALID` with
|
|
323
318
|
exact invariant codes and derived stale reasons. The persisted
|
|
324
319
|
`.forgeloop/work-state.json` schema is unchanged: `status`, `stale`, and `fresh`
|
|
@@ -379,12 +374,17 @@ target project. Its main threat boundaries are:
|
|
|
379
374
|
| Data exposure | Receipts and checkpoints reject secret-like keys and values; examples use placeholders, and the repository secret scanner runs in CI. |
|
|
380
375
|
| Unsafe update overwrite | `update` preserves locally modified files and the target's `.forgeloop/kit/PROJECT_PROFILE.md`; adoption and writes remain bounded to the selected target. |
|
|
381
376
|
| Dependency supply chain | Runtime code uses Node built-ins only; the package does not install agents, providers, plugins, or remote services. |
|
|
377
|
+
| Installation authority provenance | Standalone CLI uses `trustMode: NONE`: environment-selected `FORGELOOP_AUTHORITY_FILE`/`FORGELOOP_AUTHORITY_DIR` sources are untrusted candidates; only an internal `HOST_ATTESTED` context may select a trusted source outside the actor-writable target. Project-local authority claims remain untrusted. |
|
|
382
378
|
| Stale replay | Work state records contract and repository fingerprints; drift requires revalidation and never reruns destructive or publication actions automatically. |
|
|
383
379
|
| Unverified publication | Receipts carry explicit publication booleans; local success never implies a push, pull request, merge, release, or deployment. |
|
|
384
380
|
|
|
385
381
|
The full boundary inventory, residual limitations, and executable evidence are
|
|
386
382
|
in [`THREAT_MODEL.md`](./THREAT_MODEL.md).
|
|
387
383
|
|
|
384
|
+
An external path is not equivalent to external authority ownership. Actor-controlled
|
|
385
|
+
environment configuration is not sufficient proof of host/operator authority;
|
|
386
|
+
trusted authority requires a host-attested integration boundary.
|
|
387
|
+
|
|
388
388
|
The CLI cannot protect a target from a separately privileged or hostile process
|
|
389
389
|
that changes the filesystem after validation. Consumers must still review
|
|
390
390
|
permissions, package provenance, and external actions before granting authority.
|
|
@@ -575,8 +575,8 @@ installed automatically.
|
|
|
575
575
|
|
|
576
576
|
## Optional multimodal capabilities
|
|
577
577
|
|
|
578
|
-
[Qwen-MM-Plugins](https://github.com/QwenLM/Qwen-MM-Plugins) can extend
|
|
579
|
-
|
|
578
|
+
[Qwen-MM-Plugins](https://github.com/QwenLM/Qwen-MM-Plugins) can extend an
|
|
579
|
+
execution environment with skills and optional MCP servers. Before using a
|
|
580
580
|
multimodal or media operation, the agent checks the model and harness for a
|
|
581
581
|
callable native capability. If the task requires a missing keyless capability,
|
|
582
582
|
the agent installs only the smallest matching `qwen-mm-plugins-<cap>` capability
|
package/THREAT_MODEL.md
CHANGED
|
@@ -33,6 +33,12 @@ remaining trust boundaries and their executable evidence.
|
|
|
33
33
|
| Runtime self-exemption | An execution environment discovers ForgeLoop but decides that the protocol does not apply because the environment is not named in documentation | Project adapter discovery and runtime interpretation | Universal applicability marker, capability-based integration, explicit unknown-runtime rule, no finite eligibility allowlist | A non-compliant runtime can ignore project instructions entirely | `tests/discovery-surfaces.test.js`, `tests/test_workflow_policy.py` |
|
|
34
34
|
| Blind oracle exposure | The system under test reads expected route/gate/evidence answers from the installed package and contaminates a blind conformance run | Published npm package and agent-readable target workspace | Exclude conformance oracles from npm package, tarball leak scan in `pack:check`, external harness-owned oracle | A misconfigured external harness may still copy oracle material into target | `tests/package.test.js`, `conformance/README.md` |
|
|
35
35
|
| Lifecycle simulation after CLI resolution failure | A runtime manually writes protocol-owned JSON and falsely claims conformance when the CLI is unresolved | Lifecycle-owned protocol state and CLI availability | CLI-owned artifact policy, universal adapter prohibition, validator-backed completion, append-only ledger hash chain | A privileged local process can tamper with local files; ForgeLoop detects consistency, not remote attestation | `tests/discovery-surfaces.test.js`, `tests/lifecycle.test.js`, `LOOP_ENGINEERING.md` |
|
|
36
|
+
| Unauthorized verification dependency installation | The active actor mutates the environment by downloading or installing a missing checker merely to satisfy verification | Verification capability discovery and installation authority | Missing verification tool policy, non-installing resolution first, explicit installation authority, equivalent-check fallback, NOT_VERIFIED degradation | A privileged external process may still install tools outside ForgeLoop's control | `tests/verification-capability.test.js`, `tests/discovery-surfaces.test.js`, `LOOP_ENGINEERING.md` |
|
|
37
|
+
| False delegation requirement | A valid single-actor run is incorrectly reported as incomplete because a validator demands artifacts for delegation that never occurred | Validator delegation scope resolution | Canonical delegationIsInScope predicate, conditional delegation validation in validateTaskArtifactSet and validate-protocol | Malformed or externally injected artifacts may require INCONSISTENT classification | `tests/conformance.test.js`, `tests/validate-protocol-cli.test.js` |
|
|
38
|
+
| Self-asserted authority bypass | The active actor supplies `installationAuthorized=true` inside its own verification evidence and thereby grants itself authority | Authority provenance and verification evidence | Boolean claims are ignored; scoped authority references, task/type/tool validation, and validator revalidation in `record-check`/`audit`/`complete` require a trusted source | A host-controlled source is still a semantic trust boundary and is not cryptographic attestation | `tests/verification-capability.test.js`, `tests/authority.test.js`, `tests/stale-receipt-recovery.test.js` |
|
|
39
|
+
| Forged local authority artifact | The active actor creates `.forgeloop/authorities/auth-modlens.json`, claims `source=operator`, and uses the reference to authorize its own installation-capable check | Host/operator authority source versus actor-writable project state | Resolve grants only from an explicit `HOST_ATTESTED` runtime context with an external source outside the target; reject project-local grants with `E_AUTHORITY_UNTRUSTED_SOURCE`; revalidate in `record-check`/`audit`/`complete` | If the host exposes the attested source as writable to the actor, ForgeLoop cannot distinguish genuine grants from actor fabrication without a stronger trust anchor | Local fake rejection, host-attested external acceptance, inside-target rejection, post-record removal and revocation tests |
|
|
40
|
+
| Environment-injected trust root | The active actor creates an authority file outside the project target and sets `FORGELOOP_AUTHORITY_FILE` or `FORGELOOP_AUTHORITY_DIR` when invoking ForgeLoop | Actor-controlled process environment versus host-attested runtime authority | Standalone CLI uses `trustMode: NONE`; environment-selected sources are metadata/candidates only and fail with `E_AUTHORITY_UNTRUSTED_SOURCE`; trusted authority requires an internal `HOST_ATTESTED` context not exposed as a self-assertable CLI option | If the host integration allows the actor to mutate or replace the attested source/context, the host trust boundary is compromised | Environment-injection rejection, standalone audit/complete rejection, host-attested positive path |
|
|
41
|
+
| Stale receipt recovery dead-end | Work state changes after preparing a receipt, leaving a mismatch that cannot be refreshed because the old receipt is rejected during re-preparation | Preparation lifecycle and recovery action resolution | Recoverable stale receipt binding in `prepareCompletion`, executable `PREPARE_COMPLETION` return from `next`, atomic refresh of stateFingerprint and changedPaths | Manual file corruption outside CLI commands requires manual diagnostic recovery | `tests/stale-receipt-recovery.test.js`, `tests/next-executability.test.js` |
|
|
36
42
|
|
|
37
43
|
## Boundary rules
|
|
38
44
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "forgeloop://schemas/authority.schema.json",
|
|
4
|
+
"title": "ForgeLoop installation authority grant",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": [
|
|
7
|
+
"schemaVersion",
|
|
8
|
+
"protocolVersion",
|
|
9
|
+
"authorityId",
|
|
10
|
+
"taskId",
|
|
11
|
+
"type",
|
|
12
|
+
"status",
|
|
13
|
+
"scope",
|
|
14
|
+
"source"
|
|
15
|
+
],
|
|
16
|
+
"properties": {
|
|
17
|
+
"schemaVersion": { "const": 1 },
|
|
18
|
+
"protocolVersion": { "const": 1 },
|
|
19
|
+
"authorityId": { "type": "string", "minLength": 1 },
|
|
20
|
+
"taskId": { "type": "string", "minLength": 1 },
|
|
21
|
+
"type": { "enum": ["SOFTWARE_INSTALLATION"] },
|
|
22
|
+
"status": { "enum": ["AUTHORIZED", "REVOKED", "EXPIRED"] },
|
|
23
|
+
"scope": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"required": ["tool"],
|
|
26
|
+
"properties": {
|
|
27
|
+
"tool": { "type": "string", "minLength": 1 }
|
|
28
|
+
},
|
|
29
|
+
"additionalProperties": false
|
|
30
|
+
},
|
|
31
|
+
"source": { "enum": ["operator", "host", "project-policy"] }
|
|
32
|
+
},
|
|
33
|
+
"additionalProperties": false
|
|
34
|
+
}
|
package/src/commands/inspect.js
CHANGED
|
@@ -8,6 +8,8 @@ export function formatInspectResult(report) {
|
|
|
8
8
|
`Manifest: ${report.manifest.status}`,
|
|
9
9
|
`Profile: ${report.profile.mode ?? "unknown"}/${report.profile.status ?? "unknown"}`,
|
|
10
10
|
`Protocol: v${report.protocol.version}`,
|
|
11
|
+
`Authority source: ${report.authority.sourceType ?? "none configured"} / ${report.authority.trusted ? "TRUSTED" : report.authority.trustMode === "NONE" ? "UNATTESTED" : "UNTRUSTED"}`,
|
|
12
|
+
`Authority trust: ${report.authority.trustMode}`,
|
|
11
13
|
`State: ${report.state.status}`,
|
|
12
14
|
`Adapters: ${report.adapters.detected.length} detected`,
|
|
13
15
|
`Findings: ${report.findings.length}`,
|
|
@@ -2,8 +2,8 @@ import { prepareCompletion as prepareCompletionArtifacts } from "../core/complet
|
|
|
2
2
|
|
|
3
3
|
export { prepareCompletionArtifacts as prepareCompletion };
|
|
4
4
|
|
|
5
|
-
export async function runPrepareCompletion({ target, packageRoot }) {
|
|
6
|
-
return prepareCompletionArtifacts({ target, packageRoot });
|
|
5
|
+
export async function runPrepareCompletion({ target, packageRoot, authorityContext, runtimeContext }) {
|
|
6
|
+
return prepareCompletionArtifacts({ target, packageRoot, authorityContext, runtimeContext });
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export function formatPrepareCompletionResult(result) {
|
|
@@ -97,14 +97,6 @@ export async function runValidateProtocol({
|
|
|
97
97
|
const stateClassification = state && readErrors.length === 0 && !stateValidationError
|
|
98
98
|
? await classifyLoadedWorkState({ target, state, contractFile })
|
|
99
99
|
: null;
|
|
100
|
-
const result = validateTaskArtifactSet({
|
|
101
|
-
route,
|
|
102
|
-
state,
|
|
103
|
-
stateClassification,
|
|
104
|
-
receipt,
|
|
105
|
-
taskBriefs,
|
|
106
|
-
delegatedResults,
|
|
107
|
-
});
|
|
108
100
|
let readyConsistencyErrors = [];
|
|
109
101
|
try {
|
|
110
102
|
const persistedPreflight = await readJsonArtifact(target, ARTIFACT_PATHS.preflight, "preflight", packageRoot);
|
|
@@ -119,9 +111,11 @@ export async function runValidateProtocol({
|
|
|
119
111
|
} catch {
|
|
120
112
|
// A missing or invalid preflight is already outside the optional protocol set.
|
|
121
113
|
}
|
|
114
|
+
let ledgerEvents = [];
|
|
122
115
|
let ledgerErrors = [];
|
|
123
116
|
if (state && !stateValidationError) {
|
|
124
117
|
const ledger = await validateEventLedger(target, packageRoot);
|
|
118
|
+
ledgerEvents = ledger.events ?? [];
|
|
125
119
|
ledgerErrors = [
|
|
126
120
|
...ledger.errors.map((error) => ({ ...error, artifacts: [ARTIFACT_PATHS.events] })),
|
|
127
121
|
...validateStateLedgerCoherence(state, ledger.events).map((error) => ({
|
|
@@ -130,6 +124,15 @@ export async function runValidateProtocol({
|
|
|
130
124
|
})),
|
|
131
125
|
];
|
|
132
126
|
}
|
|
127
|
+
const result = validateTaskArtifactSet({
|
|
128
|
+
route,
|
|
129
|
+
state,
|
|
130
|
+
stateClassification,
|
|
131
|
+
receipt,
|
|
132
|
+
taskBriefs,
|
|
133
|
+
delegatedResults,
|
|
134
|
+
events: ledgerEvents,
|
|
135
|
+
});
|
|
133
136
|
if (readErrors.length > 0 || schemaErrors.length > 0 || readyConsistencyErrors.length > 0 || ledgerErrors.length > 0) {
|
|
134
137
|
return {
|
|
135
138
|
...result,
|
package/src/core/audit.js
CHANGED
|
@@ -34,8 +34,8 @@ async function compareChangedPaths(target, packageRoot) {
|
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export async function evaluateAudit({ target, packageRoot, strict = false } = {}) {
|
|
38
|
-
const completion = await evaluateCompletion({ target, packageRoot, strict });
|
|
37
|
+
export async function evaluateAudit({ target, packageRoot, strict = false, authorityContext, runtimeContext } = {}) {
|
|
38
|
+
const completion = await evaluateCompletion({ target, packageRoot, strict, authorityContext, runtimeContext });
|
|
39
39
|
let manifest = null;
|
|
40
40
|
let manifestError = null;
|
|
41
41
|
try {
|
package/src/core/checks.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PROTOCOL_VERSION } from "./protocol.js";
|
|
2
|
+
import { validateVerificationAuthority } from "./verification-capability.js";
|
|
2
3
|
|
|
3
4
|
export const CHECK_SCHEMA_VERSION = 1;
|
|
4
5
|
export const CHECK_STATUSES = Object.freeze(["passed", "failed", "blocked", "not-run"]);
|
|
@@ -45,7 +46,7 @@ function assertCompoundStatus(value, label) {
|
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
export function createCheck(input = {}) {
|
|
49
|
+
export function createCheck(input = {}, options = {}) {
|
|
49
50
|
const check = {
|
|
50
51
|
schemaVersion: CHECK_SCHEMA_VERSION,
|
|
51
52
|
protocolVersion: PROTOCOL_VERSION,
|
|
@@ -61,10 +62,10 @@ export function createCheck(input = {}) {
|
|
|
61
62
|
...(input.viewport !== undefined ? { viewport: structuredClone(input.viewport) } : {}),
|
|
62
63
|
...(input.details !== undefined ? { details: structuredClone(input.details) } : {}),
|
|
63
64
|
};
|
|
64
|
-
return assertCheck(check);
|
|
65
|
+
return assertCheck(check, "check", options);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
export function assertCheck(value, label = "check") {
|
|
68
|
+
export function assertCheck(value, label = "check", options = {}) {
|
|
68
69
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
69
70
|
throw checkError("E_CHECK_INVALID", `${label} must be an object`);
|
|
70
71
|
}
|
|
@@ -97,15 +98,21 @@ export function assertCheck(value, label = "check") {
|
|
|
97
98
|
if (value.status === "not-run" && value.evidenceKind !== "NOT_VERIFIED") {
|
|
98
99
|
throw contradiction(`${label} not-run must use NOT_VERIFIED evidence`);
|
|
99
100
|
}
|
|
101
|
+
if (value.status === "passed") {
|
|
102
|
+
const auth = validateVerificationAuthority(value, options);
|
|
103
|
+
if (!auth.valid) {
|
|
104
|
+
throw checkError(auth.error.code, auth.error.message);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
100
107
|
assertCompoundStatus(value, label);
|
|
101
108
|
return value;
|
|
102
109
|
}
|
|
103
110
|
|
|
104
|
-
export function assertCheckList(value, label = "checks") {
|
|
111
|
+
export function assertCheckList(value, label = "checks", options = {}) {
|
|
105
112
|
if (!Array.isArray(value)) throw checkError("E_CHECK_INVALID", `${label} must be an array`);
|
|
106
113
|
const ids = new Set();
|
|
107
114
|
value.forEach((item, index) => {
|
|
108
|
-
assertCheck(item, `${label}[${index}]
|
|
115
|
+
assertCheck(item, `${label}[${index}]`, options);
|
|
109
116
|
if (ids.has(item.id)) throw checkError("E_CHECK_INVALID", `${label} contains duplicate id ${item.id}`);
|
|
110
117
|
ids.add(item.id);
|
|
111
118
|
});
|