@really-knows-ai/foundry 3.8.4 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.opencode/plugins/foundry-tools/stage-output-tool.js +113 -0
- package/dist/.opencode/plugins/foundry-tools/stage-tools.js +98 -21
- package/dist/.opencode/plugins/foundry.js +2 -0
- package/dist/CHANGELOG.md +33 -0
- package/dist/docs/architecture.md +1 -1
- package/dist/scripts/appraise-module.js +76 -74
- package/dist/scripts/lib/forge-contract.js +13 -13
- package/dist/scripts/lib/stage-output-schemas.js +174 -0
- package/dist/scripts/orchestrate-cycle.js +6 -6
- package/dist/scripts/orchestrate-dispatch.js +240 -0
- package/dist/scripts/orchestrate-finalise.js +21 -17
- package/dist/scripts/orchestrate-phases.js +3 -3
- package/dist/scripts/orchestrate.js +10 -92
- package/dist/skills/appraise/SKILL.md +9 -27
- package/dist/skills/assay/SKILL.md +6 -13
- package/dist/skills/forge/SKILL.md +10 -11
- package/dist/skills/human-appraise/SKILL.md +144 -57
- package/dist/skills/orchestrate/SKILL.md +2 -2
- package/dist/skills/quench/SKILL.md +5 -5
- package/package.json +1 -1
|
@@ -21,9 +21,9 @@ Before running this skill, verify that the `foundry/` directory exists in the pr
|
|
|
21
21
|
Appraise runs inside an enforced stage. Your **first** and **last** tool calls are fixed:
|
|
22
22
|
|
|
23
23
|
1. **First:** `foundry_stage_begin({stage, cycle, token})` — copy the token verbatim from the dispatch prompt. No other tool call is permitted before this one.
|
|
24
|
-
2. **Last:** `foundry_stage_end(
|
|
24
|
+
2. **Last:** `foundry_stage_end()`.
|
|
25
25
|
|
|
26
|
-
Appraise makes **no disk writes**. Feedback output flows through
|
|
26
|
+
Appraise makes **no disk writes**. Feedback output flows through `foundry_stage_output` calls. The orchestrator's internal consolidate step reads the outputs, posts feedback, and resolves prior items.
|
|
27
27
|
|
|
28
28
|
## Protocol
|
|
29
29
|
|
|
@@ -35,43 +35,25 @@ Appraise makes **no disk writes**. Feedback output flows through JSONL returned
|
|
|
35
35
|
6. Evaluate each file against each law. For each law, either:
|
|
36
36
|
- Note no issues (pass)
|
|
37
37
|
- Describe the violation, quoting evidence from the artefact
|
|
38
|
-
7.
|
|
39
|
-
|
|
40
|
-
```json
|
|
41
|
-
{"file": "<path>", "law": "<law-slug>", "text": "<issue description>", "evidence": "<quote from artefact>"}
|
|
42
|
-
```
|
|
43
|
-
|
|
38
|
+
7. For each violation, call `foundry_stage_output({ file, law, text, evidence })`.
|
|
44
39
|
`file` and `text` are required. `law` and `evidence` are recommended — `law` tells the orchestrator which law tag to use, `evidence` quotes the offending passage. Optional extra fields (`severity`, `location`) are passed through unchanged.
|
|
45
40
|
|
|
46
|
-
If
|
|
47
|
-
|
|
48
|
-
Your response text is ONLY JSONL — one JSON object per line. No markdown headings, no code blocks, no commentary, no YAML.
|
|
49
|
-
|
|
50
|
-
8. `foundry_stage_end({summary})`. The summary describes how many issues were found (e.g. "3 issues found" or "No issues found").
|
|
51
|
-
|
|
52
|
-
## Output examples
|
|
53
|
-
|
|
54
|
-
Good (issues found):
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
{"file": "haikus/mountain.md", "law": "syllable-count", "text": "Line 2 has 8 syllables, expected 7", "evidence": "A frog jumps into the pond", "location": "2:1"}
|
|
58
|
-
{"file": "haikus/mountain.md", "law": "nature-imagery", "text": "Contains industrial imagery violating nature-only requirement", "evidence": "The rusty old machine"}
|
|
59
|
-
```
|
|
41
|
+
If no issues, call `foundry_stage_end()` directly — no `stage_output` calls needed.
|
|
60
42
|
|
|
61
|
-
|
|
43
|
+
Do NOT write JSONL as text. Call the tool.
|
|
62
44
|
|
|
63
|
-
(
|
|
45
|
+
8. `foundry_stage_end()`.
|
|
64
46
|
|
|
65
47
|
## Feedback handling
|
|
66
48
|
|
|
67
|
-
You do NOT call `foundry_feedback_add` or `foundry_feedback_resolve`. The orchestrator's consolidate step reads your
|
|
49
|
+
You do NOT call `foundry_feedback_add` or `foundry_feedback_resolve`. The orchestrator's consolidate step reads your stage outputs, de-duplicates across all appraisers, posts feedback items with tag `law:<slug>`, and resolves prior appraise-sourced feedback.
|
|
68
50
|
|
|
69
51
|
## What you do NOT do
|
|
70
52
|
|
|
71
|
-
- You do not write files — feedback output goes through
|
|
53
|
+
- You do not write files — feedback output goes through `foundry_stage_output`, not `foundry_feedback_add`.
|
|
72
54
|
- You do not revise the artefact — that is the forge skill's job.
|
|
73
55
|
- You do not run deterministic validators — that is the quench skill's job.
|
|
74
56
|
- You do not call `foundry_feedback_add`, `foundry_feedback_action`, `foundry_feedback_wontfix`, or `foundry_feedback_resolve`.
|
|
75
57
|
- You do not call `foundry_history_append` or `foundry_git_commit` — `foundry_orchestrate` handles those.
|
|
76
58
|
- You do not register artefacts — that happens automatically.
|
|
77
|
-
- You do not output YAML, markdown, or prose —
|
|
59
|
+
- You do not output YAML, markdown, or prose — use `foundry_stage_output` for structured data.
|
|
@@ -8,7 +8,7 @@ description: Deterministic population of flow memory by running project-authored
|
|
|
8
8
|
|
|
9
9
|
Runs the `assay` stage of a cycle. An assay stage executes every extractor listed in the cycle's `assay.extractors` frontmatter, in order. Each extractor is a project-authored CLI script at the path given in its definition file — see the `foundry/memory/extractors/<name>.md` files for what each one does.
|
|
10
10
|
|
|
11
|
-
The assay stage is **deterministic**. This skill does **not** interpret extractor output. It only calls `foundry_assay_run`, which handles spawning, parsing, validation, and memory upserts. On any failure (extractor non-zero exit, parse error, permission violation, timeout, or post-run memory sync failure), `foundry_assay_run` marks the workfile failed (`status: failed`) with a reason describing the failure, and returns `{error, flow_failed: true, ...}`. The cycle is over — extractor scripts live outside any artefact's `file-patterns`, so forge cannot fix them. The user must fix the extractor and start a new cycle. Your job is to wrap the lifecycle cleanly: end the stage
|
|
11
|
+
The assay stage is **deterministic**. This skill does **not** interpret extractor output. It only calls `foundry_assay_run`, which handles spawning, parsing, validation, and memory upserts. On any failure (extractor non-zero exit, parse error, permission violation, timeout, or post-run memory sync failure), `foundry_assay_run` marks the workfile failed (`status: failed`) with a reason describing the failure, and returns `{error, flow_failed: true, ...}`. The cycle is over — extractor scripts live outside any artefact's `file-patterns`, so forge cannot fix them. The user must fix the extractor and start a new cycle. Your job is to wrap the lifecycle cleanly: end the stage and stop.
|
|
12
12
|
|
|
13
13
|
## Protocol
|
|
14
14
|
|
|
@@ -22,7 +22,7 @@ Call `foundry_stage_begin({ stage, cycle, token })` with the values from the dis
|
|
|
22
22
|
|
|
23
23
|
### 2. Read WORK.md to find the extractor list
|
|
24
24
|
|
|
25
|
-
Call `foundry_workfile_get()`. Read `frontmatter.assay.extractors`. This is an ordered array of extractor names. If it is missing or empty, this is a routing bug — end the stage (step
|
|
25
|
+
Call `foundry_workfile_get()`. Read `frontmatter.assay.extractors`. This is an ordered array of extractor names. If it is missing or empty, this is a routing bug — end the stage (step 4) with an error describing the missing extractor list.
|
|
26
26
|
|
|
27
27
|
### Check for failed flow state
|
|
28
28
|
|
|
@@ -45,21 +45,14 @@ Call `foundry_assay_run({ cycle, extractors })` passing exactly those values. Do
|
|
|
45
45
|
- `{ok: true, perExtractor: [{name, rowsUpserted, durationMs}, ...]}` — all extractors succeeded.
|
|
46
46
|
- `{error, flow_failed: true, aborted: true, failedExtractor, reason, stderr, perExtractor: [...]}` — the run aborted on an extractor failure. The workfile is already marked failed; no further work is permitted until the user abandons the cycle.
|
|
47
47
|
- `{error, flow_failed: true}` — post-run memory sync failed. Same recovery path: workfile is failed, user must abandon.
|
|
48
|
-
- `{error: "..."}` (without `flow_failed`) — a precondition failed (not an active assay stage, etc.). This should not happen if step 1 succeeded; treat as an error and end the stage (step
|
|
48
|
+
- `{error: "..."}` (without `flow_failed`) — a precondition failed (not an active assay stage, etc.). This should not happen if step 1 succeeded; treat as an error and end the stage (step 4).
|
|
49
49
|
|
|
50
|
-
### 4.
|
|
50
|
+
### 4. End the stage
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
- On success: `"ran 2 extractors, upserted 47 rows in 1420ms"`.
|
|
55
|
-
- On abort: `"aborted on extractor 'java-symbols': extractor exited with exit code 2"`.
|
|
52
|
+
Call `foundry_stage_end()`. Always end the stage, whether the run succeeded or aborted. The stage lifecycle must close cleanly so the orchestrator can commit.
|
|
56
53
|
|
|
57
54
|
Do not add feedback items, do not call `foundry_feedback_add`. Assay stages cannot file feedback — extractor failure is recorded directly on the workfile (`status: failed`).
|
|
58
55
|
|
|
59
|
-
### 5. End the stage
|
|
60
|
-
|
|
61
|
-
Call `foundry_stage_end({ summary })` with the summary from step 4. Always end the stage, whether the run succeeded or aborted. The stage lifecycle must close cleanly so the orchestrator can commit.
|
|
62
|
-
|
|
63
56
|
## What this skill must not do
|
|
64
57
|
|
|
65
58
|
- **Must not** read or parse extractor output files itself.
|
|
@@ -69,4 +62,4 @@ Call `foundry_stage_end({ summary })` with the summary from step 4. Always end t
|
|
|
69
62
|
|
|
70
63
|
## If something unexpected happens
|
|
71
64
|
|
|
72
|
-
If `foundry_assay_run` throws an unrelated error (e.g. `error: memory not enabled`), that is a programming error in the cycle configuration — not an expected extractor failure. Do not retry. End the stage
|
|
65
|
+
If `foundry_assay_run` throws an unrelated error (e.g. `error: memory not enabled`), that is a programming error in the cycle configuration — not an expected extractor failure. Do not retry. End the stage and stop.
|
|
@@ -21,7 +21,7 @@ Before running this skill, verify that the `foundry/` directory exists in the pr
|
|
|
21
21
|
Forge runs inside an enforced stage. Your **first** and **last** tool calls are fixed:
|
|
22
22
|
|
|
23
23
|
1. **First:** `foundry_stage_begin({stage, cycle, token})` — the orchestrator hands you `stage`, `cycle`, and an opaque `token` string in the dispatch prompt. Copy the token verbatim; never invent, edit, or re-sign it. No other tool call is permitted before this one. Any writes before `stage_begin` will be blocked by preconditions.
|
|
24
|
-
2. **Last:** `foundry_stage_end(
|
|
24
|
+
2. **Last:** `foundry_stage_end()` — return control to the orchestrator. After `stage_end`, the orchestrator's internal finalise step scans the disk and registers your output artefact. **You do not register artefacts yourself.**
|
|
25
25
|
|
|
26
26
|
## Protocol
|
|
27
27
|
|
|
@@ -51,7 +51,7 @@ Forge runs inside an enforced stage. Your **first** and **last** tool calls are
|
|
|
51
51
|
- Read the selected files for context.
|
|
52
52
|
7. Produce the artefact, respecting all applicable laws from the start.
|
|
53
53
|
8. Write the artefact file to a location that matches the artefact type's `file-patterns`.
|
|
54
|
-
9. `
|
|
54
|
+
9. `foundry_stage_output({ status: "done" })` then `foundry_stage_end()`.
|
|
55
55
|
|
|
56
56
|
### Revision (feedback exists)
|
|
57
57
|
|
|
@@ -60,26 +60,25 @@ Forge runs inside an enforced stage. Your **first** and **last** tool calls are
|
|
|
60
60
|
3. If the cycle declares `inputs`, discover them via filesystem scan against each input type's `file-patterns` (same protocol as first-generation step 6). Re-read the relevant files — they may have changed on disk since the previous iteration (nothing in this cycle wrote to them, but the user may have modified them between iterations).
|
|
61
61
|
4. Address the single feedback item from the dispatch prompt following the feedback handling rules below.
|
|
62
62
|
5. Update the artefact file (if fixing), or skip (if WONT-FIX).
|
|
63
|
-
6. `
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
Write NOTHING else in the summary.
|
|
63
|
+
6. `foundry_stage_output({ status: "actioned" })` then `foundry_stage_end()` — file was changed to address the feedback.
|
|
64
|
+
Or: `foundry_stage_output({ status: "wont-fix", reason: "<justification>" })` then `foundry_stage_end()` — item already resolved or does not apply.
|
|
65
|
+
Call `foundry_stage_output` with the correct status object. Write nothing else — format is validated by the tool.
|
|
67
66
|
|
|
68
67
|
## Feedback handling
|
|
69
68
|
|
|
70
69
|
The dispatch prompt contains one feedback item to address.
|
|
71
70
|
|
|
72
71
|
**To fix the issue** — change the artefact file and call
|
|
73
|
-
`
|
|
72
|
+
`foundry_stage_output({ status: "actioned" })` then `foundry_stage_end()`.
|
|
74
73
|
|
|
75
74
|
**If the issue is already resolved** — call
|
|
76
|
-
`
|
|
75
|
+
`foundry_stage_output({ status: "wont-fix", reason: "<justification>" })` then `foundry_stage_end()`.
|
|
77
76
|
Do NOT change the file.
|
|
78
77
|
|
|
79
78
|
**If the issue does not apply** (appraise judgement you disagree with) — same
|
|
80
|
-
`
|
|
79
|
+
`wont-fix` flow.
|
|
81
80
|
|
|
82
|
-
The
|
|
81
|
+
The status is validated by the tool. No descriptions, no explanations.
|
|
83
82
|
|
|
84
83
|
Do NOT call `foundry_feedback_action`, `foundry_feedback_wontfix`, or
|
|
85
84
|
`foundry_feedback_resolve`. The orchestrator handles transitions automatically.
|
|
@@ -109,5 +108,5 @@ items in the list output.
|
|
|
109
108
|
- You do not register artefacts — the orchestrator's internal finalise step handles that automatically.
|
|
110
109
|
- You do not call `foundry_history_append` or `foundry_git_commit` — `foundry_orchestrate` does (those tools are not registered publicly).
|
|
111
110
|
- You do not evaluate or score the artefact.
|
|
112
|
-
- You do not mark feedback as actioned or wont-fix via tool calls — the orchestrator handles feedback transitions based on your artefact changes and
|
|
111
|
+
- You do not mark feedback as actioned or wont-fix via tool calls — the orchestrator handles feedback transitions based on your artefact changes and stage output.
|
|
113
112
|
- You do not write to any file outside the output artefact type's `file-patterns` (plus `WORK.md` / `WORK.feedback.yaml` / `WORK.history.yaml`). Input files are read-only unless the output type's patterns happen to cover them.
|
|
@@ -19,7 +19,7 @@ Before running this skill, verify that the `foundry/` directory exists in the pr
|
|
|
19
19
|
Human-appraise runs inside an enforced stage. Your **first** and **last** tool calls are fixed:
|
|
20
20
|
|
|
21
21
|
1. **First:** `foundry_stage_begin({stage, cycle, token})` — copy the token verbatim from the dispatch prompt.
|
|
22
|
-
2. **Last:** `foundry_stage_end(
|
|
22
|
+
2. **Last:** `foundry_stage_end()`.
|
|
23
23
|
|
|
24
24
|
Human-appraise makes **no disk writes**. All output flows through `foundry_feedback_add` and `foundry_feedback_resolve`. `foundry_stage_end` flags unexpected writes as a violation.
|
|
25
25
|
|
|
@@ -35,83 +35,170 @@ When invoked from orchestrate, you receive `{cycle, token, context}`:
|
|
|
35
35
|
|
|
36
36
|
Your FIRST tool call must be `foundry_stage_begin({stage: 'human-appraise:<cycle>', cycle, token})`.
|
|
37
37
|
|
|
38
|
-
Your
|
|
38
|
+
Your last tool calls must be `foundry_stage_output({ verdict: "approved" })` then `foundry_stage_end()`. The verdict is communicated through `foundry_stage_output` before the stage is closed.
|
|
39
39
|
|
|
40
40
|
## Protocol
|
|
41
41
|
|
|
42
|
+
### Step 1: Gather context
|
|
43
|
+
|
|
42
44
|
1. `foundry_stage_begin(...)`.
|
|
43
|
-
2.
|
|
44
|
-
|
|
45
|
+
2. `foundry_workfile_get` — current state, goal, cycle.
|
|
46
|
+
|
|
47
|
+
**Check for failed flow state.** If `foundry_workfile_get` returns `{status: "failed", reason: ...}`, STOP. Do not do any substantive work. Tell the user:
|
|
48
|
+
|
|
49
|
+
> The flow is in a failed state. Reason: `<reason>`.
|
|
50
|
+
>
|
|
51
|
+
> No further work is permitted. To recover:
|
|
52
|
+
>
|
|
53
|
+
> 1. `foundry_workfile_delete({confirm: true})` to abandon the cycle.
|
|
54
|
+
> 2. Back out to main (`git checkout main`) and delete the work branch.
|
|
55
|
+
> 3. Investigate and fix the root cause of the failure before restarting.
|
|
56
|
+
|
|
57
|
+
Then call `foundry_stage_end()`, return control to the user, and stop.
|
|
58
|
+
|
|
59
|
+
3. `foundry_artefacts_list({})` — this cycle's branch artefact changes as `[{ file, state }]` entries.
|
|
60
|
+
4. `foundry_feedback_list` — all existing feedback items.
|
|
61
|
+
5. `foundry_history_list({cycle: <current-cycle>})` — what has happened so far.
|
|
62
|
+
|
|
63
|
+
### Step 2: Classify feedback
|
|
64
|
+
|
|
65
|
+
Split the feedback list into two categories by `state`:
|
|
66
|
+
- **Resolved**: `state === 'resolved'` — no action needed, informational only.
|
|
67
|
+
- **Unresolved**: all other states (`open`, `rejected`, `actioned`, `wont-fix`).
|
|
68
|
+
|
|
69
|
+
### Step 3: Route to the correct review mode
|
|
70
|
+
|
|
71
|
+
- **If there are NO unresolved feedback items** → go to **Mode A: Clean review**.
|
|
72
|
+
- **If there ARE unresolved feedback items** → go to **Mode B: Feedback review**.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Mode A: Clean review (no unresolved feedback)
|
|
77
|
+
|
|
78
|
+
The cycle is in good shape — all feedback from appraisers and quench has been addressed. You present the artefact summary only, not the full content.
|
|
79
|
+
|
|
80
|
+
### A.1 Show the artefact summary
|
|
81
|
+
|
|
82
|
+
Get the artefact type's file-patterns: call `foundry_config_artefact_type` with the cycle's output type (from `foundry_workfile_get`). The response includes `file-patterns` — glob patterns for this artefact type (e.g. `["haikus/*.md"]`).
|
|
83
|
+
|
|
84
|
+
Run `git diff --stat main..HEAD` restricted to only those files by passing each glob as a pathspec:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
git diff --stat main..HEAD -- haikus/*.md
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Example output:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
haikus/sunburn.md | 4 +++-
|
|
94
|
+
1 file changed, 4 insertions(+), 1 deletion(-)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Also show the goal from `foundry_workfile_get` so the user knows what was being produced.
|
|
98
|
+
|
|
99
|
+
### A.2 Ask the user
|
|
45
100
|
|
|
46
|
-
|
|
101
|
+
Use the **question tool** (NOT a plain text prompt — the question tool pauses and waits for the user):
|
|
47
102
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
>
|
|
52
|
-
> 1. `foundry_workfile_delete({confirm: true})` to abandon the cycle.
|
|
53
|
-
> 2. Back out to main (`git checkout main`) and delete the work branch.
|
|
54
|
-
> 3. Investigate and fix the root cause of the failure before restarting.
|
|
103
|
+
```
|
|
104
|
+
header: "Review changes"
|
|
105
|
+
question: "The cycle finished with no unresolved feedback. Here are the changes:
|
|
55
106
|
|
|
56
|
-
|
|
57
|
-
- `foundry_artefacts_list({})` — this cycle's branch artefact changes as `[{ file, state }]` entries
|
|
58
|
-
- `foundry_feedback_list` — all existing feedback
|
|
59
|
-
- `foundry_history_list({cycle: <current-cycle>})` — what has happened so far
|
|
107
|
+
<diff stat output>
|
|
60
108
|
|
|
61
|
-
|
|
109
|
+
Goal: <goal from workfile>
|
|
62
110
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
111
|
+
What would you like to do?"
|
|
112
|
+
options:
|
|
113
|
+
- label: "Approve"
|
|
114
|
+
description: "Looks good — close the cycle as done"
|
|
115
|
+
- label: "Provide feedback"
|
|
116
|
+
description: "Send feedback to forge for another iteration"
|
|
117
|
+
```
|
|
67
118
|
|
|
68
|
-
|
|
119
|
+
### A.3 Act on response
|
|
69
120
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- **Provide feedback** — `foundry_feedback_add({ file, text, tag: 'human' })`. Sort will route back to forge.
|
|
73
|
-
- **Resolve feedback** — `foundry_feedback_resolve({ id, resolution, reason? })` for items in `{actioned, wont-fix}`. See "Feedback handling" below for the legal transitions and authority rules.
|
|
74
|
-
- **Abort** — human-appraise cannot directly mark the artefact `blocked` (the repository no longer has a per-artefact status tool or table). To abort: end the stage with a summary explaining the abort, then either (a) instruct the user to call `foundry_workfile_delete({ confirm: true })` to discard the cycle, or (b) reject outstanding feedback so routing exhausts iterations and sort blocks the cycle on its own.
|
|
121
|
+
- **Approve**: No feedback added. Call `foundry_stage_output({ verdict: "approved" })` then `foundry_stage_end()`. Sort will route to `done`.
|
|
122
|
+
- **Provide feedback**: Ask the user what needs changing (the user types their feedback). Then call `foundry_feedback_add({ file: '<artefact-file>', text: '<user feedback>', tag: 'human' })`. Call `foundry_stage_end()`. Sort will route to forge.
|
|
75
123
|
|
|
76
|
-
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Mode B: Feedback review (unresolved feedback exists)
|
|
127
|
+
|
|
128
|
+
The cycle has outstanding feedback from appraisers, quench, or prior human reviews. You present each item to the user for a verdict.
|
|
129
|
+
|
|
130
|
+
### B.1 Summarise the state
|
|
131
|
+
|
|
132
|
+
Briefly tell the user how many unresolved items exist and what the goal is.
|
|
133
|
+
|
|
134
|
+
### B.2 Review each unresolved item
|
|
135
|
+
|
|
136
|
+
Present each unresolved item **one at a time** using the **question tool**. For each item:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
header: "Feedback N of M"
|
|
140
|
+
question: "Feedback item:
|
|
141
|
+
|
|
142
|
+
File: <file>
|
|
143
|
+
Source: <source stage>
|
|
144
|
+
Tag: <tag>
|
|
145
|
+
Issue: <text>
|
|
146
|
+
|
|
147
|
+
<if the item has a reason, show: "Reason: <reason>">
|
|
148
|
+
|
|
149
|
+
Do you agree with this feedback?"
|
|
150
|
+
options:
|
|
151
|
+
- label: "Agree"
|
|
152
|
+
description: "This needs fixing — let forge handle it"
|
|
153
|
+
- label: "Disagree"
|
|
154
|
+
description: "Override this item — resolve it"
|
|
155
|
+
- label: "Comment"
|
|
156
|
+
description: "Add my own note or context about this item"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
After the user responds:
|
|
160
|
+
|
|
161
|
+
- **Agree**: Do nothing — the item stays in its current state. Sort will route to forge to address it.
|
|
162
|
+
- **Disagree**: Call `foundry_feedback_resolve({ id: '<item-id>', resolution: 'approved' })`. Optionally pass a `reason`.
|
|
163
|
+
- **Comment**: Ask the user what they want to say. Then call `foundry_feedback_add({ file: '<file>', text: '<user comment>', tag: 'human' })`. The original item stays open so forge still addresses it alongside the human comment.
|
|
164
|
+
|
|
165
|
+
Repeat for every unresolved item.
|
|
166
|
+
|
|
167
|
+
### B.3 Final question
|
|
168
|
+
|
|
169
|
+
After all unresolved items have been reviewed, ask one final question using the **question tool**:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
header: "Any other feedback?"
|
|
173
|
+
question: "All unresolved feedback items have been reviewed. Any other changes you want before the cycle continues?"
|
|
174
|
+
options:
|
|
175
|
+
- label: "None — continue"
|
|
176
|
+
description: "Proceed with the current state"
|
|
177
|
+
- label: "Add more feedback"
|
|
178
|
+
description: "Provide additional notes for forge"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
- **None — continue**: Call `foundry_stage_output({ verdict: "approved" })` then `foundry_stage_end()`.
|
|
182
|
+
- **Add more feedback**: Ask the user what they want to add, then call `foundry_feedback_add({ file: '<file>', text: '<text>', tag: 'human' })`. Then call `foundry_stage_end()`.
|
|
183
|
+
|
|
184
|
+
---
|
|
77
185
|
|
|
78
186
|
## Feedback handling
|
|
79
187
|
|
|
80
|
-
As a human-appraise stage, you can add human feedback and resolve
|
|
81
|
-
feedback items. **Human-appraise can resolve any non-resolved
|
|
82
|
-
source-stage item regardless of source** — this is the universal
|
|
83
|
-
override authority recorded in spec §5.1 rule 5.
|
|
188
|
+
As a human-appraise stage, you can add human feedback and resolve feedback items. **Human-appraise can resolve any non-resolved source-stage item regardless of source** — this is the universal override authority recorded in spec §5.1 rule 5.
|
|
84
189
|
|
|
85
190
|
What human-appraise can NOT do:
|
|
86
191
|
|
|
87
|
-
- **No forward transitions.** `foundry_feedback_action` and
|
|
88
|
-
|
|
89
|
-
`{actioned, wont-fix}` — that is forge's lane (spec §5.1 rule 1) and
|
|
90
|
-
the tools reject calls from any non-forge stage. If an open or rejected
|
|
91
|
-
item needs work, sort will route to forge after this stage ends.
|
|
92
|
-
- **No artefact status writes.** The repository no longer has a per-artefact
|
|
93
|
-
status tool or table. Status is owned by the cycle state machine through
|
|
94
|
-
sort and orchestrate routing.
|
|
192
|
+
- **No forward transitions.** `foundry_feedback_action` and `foundry_feedback_wontfix` move items from `{open, rejected}` to `{actioned, wont-fix}` — that is forge's lane (spec §5.1 rule 1) and the tools reject calls from any non-forge stage. If an open or rejected item needs work, sort will route to forge after this stage ends.
|
|
193
|
+
- **No artefact status writes.** The repository no longer has a per-artefact status tool or table. Status is owned by the cycle state machine through sort and orchestrate routing.
|
|
95
194
|
|
|
96
195
|
What human-appraise CAN do:
|
|
97
196
|
|
|
98
|
-
1. **Add new human feedback.** Call `foundry_feedback_add` with
|
|
99
|
-
`{ file, text, tag: 'human' }`. The `source` is your stage id. The tool
|
|
100
|
-
returns `{ ok: true, id, deduped }`; `deduped: true` indicates an
|
|
101
|
-
existing non-resolved item with the same `(file, tag, hash(text))` was
|
|
102
|
-
found and no new snapshot was written, `deduped: false` indicates a new
|
|
103
|
-
item was created.
|
|
197
|
+
1. **Add new human feedback.** Call `foundry_feedback_add` with `{ file, text, tag: 'human' }`. The `source` is your stage id. The tool returns `{ ok: true, id, deduped }`; `deduped: true` indicates an existing non-resolved item with the same `(file, tag, hash(text))` was found and no new snapshot was written, `deduped: false` indicates a new item was created.
|
|
104
198
|
|
|
105
|
-
2. **Resolve any non-resolved item.** For items in
|
|
106
|
-
`{actioned, wont-fix}`, call `foundry_feedback_resolve` with
|
|
107
|
-
`{ id, resolution: 'approved' | 'rejected', reason? }`. Human-appraise
|
|
108
|
-
may resolve any such item regardless of source, including items from
|
|
109
|
-
other stage ids.
|
|
199
|
+
2. **Resolve any non-resolved item.** For items in `{actioned, wont-fix}`, call `foundry_feedback_resolve` with `{ id, resolution: 'approved' | 'rejected', reason? }`. Human-appraise may resolve any such item regardless of source, including items from other stage ids.
|
|
110
200
|
|
|
111
|
-
**Reason rules.** `reason` is required when rejecting feedback
|
|
112
|
-
(`resolution: 'rejected'`). Approved resolution via
|
|
113
|
-
`foundry_feedback_resolve({ id, resolution: 'approved', reason? })` may
|
|
114
|
-
omit `reason`.
|
|
201
|
+
**Reason rules.** `reason` is required when rejecting feedback (`resolution: 'rejected'`). Approved resolution via `foundry_feedback_resolve({ id, resolution: 'approved', reason? })` may omit `reason`.
|
|
115
202
|
|
|
116
203
|
## What you do NOT do
|
|
117
204
|
|
|
@@ -119,6 +206,6 @@ omit `reason`.
|
|
|
119
206
|
- You do not make decisions for the human — present the state and wait.
|
|
120
207
|
- You do not modify the artefact.
|
|
121
208
|
- You do not skip the pause — the human must respond before continuing.
|
|
122
|
-
- You do not filter or summarise away important details — show the full picture.
|
|
123
209
|
- You do not call `foundry_history_append` or `foundry_git_commit` — `foundry_orchestrate` owns those (the tools are not registered publicly).
|
|
124
|
-
- You do not register artefacts — handled by `foundry_stage_end(
|
|
210
|
+
- You do not register artefacts — handled by `foundry_stage_end()`.
|
|
211
|
+
- You do not present the full artefact file content — the human can inspect files themselves if curious. Show summaries only.
|
|
@@ -82,7 +82,7 @@ module handles lifecycle internally.
|
|
|
82
82
|
|
|
83
83
|
Payload: `{stage, token, context}`.
|
|
84
84
|
|
|
85
|
-
Invoke the `human-appraise` skill inline, passing `{cycle, token, context}`. The skill will prompt the user, collect feedback, and call `
|
|
85
|
+
Invoke the `human-appraise` skill inline, passing `{cycle, token, context}`. The skill will prompt the user, collect feedback, and call `foundry_stage_output({ verdict: "approved" })` then `foundry_stage_end()`.
|
|
86
86
|
|
|
87
87
|
When it returns, call `foundry_orchestrate({lastResult: {ok: true}})`.
|
|
88
88
|
|
|
@@ -117,7 +117,7 @@ Report to the user: "Cycle halted (violation): `<details>`. Affected files: `<af
|
|
|
117
117
|
|
|
118
118
|
The orchestrator manages forge feedback transitions directly. After each
|
|
119
119
|
forge subagent completes, `enforceForgeStage` inspects the outcome — a
|
|
120
|
-
version change or a
|
|
120
|
+
version change or a wont-fix status in the stage output — and transitions the
|
|
121
121
|
feedback item to `actioned` or `wont-fix`. Forge subagents do not call
|
|
122
122
|
`foundry_feedback_action` or `foundry_feedback_wontfix`; those are the
|
|
123
123
|
orchestrator's responsibility. If you want to inspect feedback state for
|
|
@@ -19,7 +19,7 @@ Before running this skill, verify that the `foundry/` directory exists in the pr
|
|
|
19
19
|
Quench runs inside an enforced stage. Your **first** and **last** tool calls are fixed:
|
|
20
20
|
|
|
21
21
|
1. **First:** `foundry_stage_begin({stage, cycle, token})` — copy the token verbatim from the dispatch prompt. Any other tool call before this will be blocked.
|
|
22
|
-
2. **Last:** `foundry_stage_end(
|
|
22
|
+
2. **Last:** `foundry_stage_end()`.
|
|
23
23
|
|
|
24
24
|
Quench makes **no disk writes**. You produce feedback via `foundry_feedback_add`, never by creating or modifying files. The orchestrator's internal finalize step (run after `stage_end`) will flag any unexpected writes as a violation.
|
|
25
25
|
|
|
@@ -43,11 +43,11 @@ Quench makes **no disk writes**. You produce feedback via `foundry_feedback_add`
|
|
|
43
43
|
4. For each artefact change:
|
|
44
44
|
a. `foundry_validate_run({ typeId: '<type-id>' })` — executes all law-based validators for the artefact type. The tool returns `{ ok, validatorsRun, items, errors }`. `items` is the array of parsed feedback items; each entry carries `lawId`, `validatorId`, `file`, and `text` (plus optional `location` and `severity`). `errors` carries validator-level failures with `lawId`, `validatorId`, `type` (`parse` or `pattern-mismatch`), and `message`.
|
|
45
45
|
b. For each entry in `items`: call `foundry_feedback_add` with `{ file: item.file, text: item.text, tag: 'law:' + item.lawId + ':' + item.validatorId }`. The tag uses the law ID and validator ID returned by the tool so operators reading `WORK.feedback.yaml` can identify exactly which validator produced each item.
|
|
46
|
-
c. If `errors` is non-empty, the validators themselves misbehaved (malformed JSONL or files outside the artefact type's `file-patterns`). Report these to the user
|
|
46
|
+
c. If `errors` is non-empty, the validators themselves misbehaved (malformed JSONL or files outside the artefact type's `file-patterns`). Report these to the user; do not convert them to law-tagged feedback.
|
|
47
47
|
5. Call `foundry_feedback_list`. For items whose `source` matches your stage id and whose state is `actioned` or `wont-fix`, use the validation results from step 4 to resolve them by id: approve when the relevant validation now passes or the deterministic issue is gone; reject with a reason when it still fails.
|
|
48
48
|
6. If every command passes for every artefact change, add no new feedback.
|
|
49
|
-
7. If the artefact list is empty, `foundry_stage_end(
|
|
50
|
-
8. `foundry_stage_end(
|
|
49
|
+
7. If the artefact list is empty, `foundry_stage_end()` and stop.
|
|
50
|
+
8. `foundry_stage_end()`.
|
|
51
51
|
|
|
52
52
|
## Feedback handling
|
|
53
53
|
|
|
@@ -86,7 +86,7 @@ deadlocked items (only human-appraise can override those).
|
|
|
86
86
|
|
|
87
87
|
## History
|
|
88
88
|
|
|
89
|
-
Do NOT call `foundry_history_append` or `foundry_git_commit` — `foundry_orchestrate` handles those (the tools are not registered publicly).
|
|
89
|
+
Do NOT call `foundry_history_append` or `foundry_git_commit` — `foundry_orchestrate` handles those (the tools are not registered publicly).
|
|
90
90
|
|
|
91
91
|
## What you do NOT do
|
|
92
92
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@really-knows-ai/foundry",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "A skill-driven framework for governed artefact generation with AI coding tools. Define your own artefact types, laws, and flows — Foundry handles the forge → quench → appraise pipeline with deterministic routing, quality gates, and iterative refinement.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/.opencode/plugins/foundry.js",
|