@really-knows-ai/foundry 2.3.2 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +180 -369
  2. package/dist/.opencode/plugins/foundry-tools/appraiser-tools.js +28 -0
  3. package/dist/.opencode/plugins/foundry-tools/artefact-tools.js +58 -0
  4. package/dist/.opencode/plugins/foundry-tools/assay-tools.js +92 -0
  5. package/dist/.opencode/plugins/foundry-tools/attestation-tools.js +191 -0
  6. package/dist/.opencode/plugins/foundry-tools/config-create-tools.js +128 -0
  7. package/dist/.opencode/plugins/foundry-tools/config-law-tools.js +380 -0
  8. package/dist/.opencode/plugins/foundry-tools/config-tools.js +43 -0
  9. package/dist/.opencode/plugins/foundry-tools/feedback-tools.js +234 -0
  10. package/dist/.opencode/plugins/foundry-tools/git-helpers.js +354 -0
  11. package/dist/.opencode/plugins/foundry-tools/git-tools.js +181 -0
  12. package/dist/.opencode/plugins/foundry-tools/helpers.js +340 -0
  13. package/dist/.opencode/plugins/foundry-tools/history-tools.js +20 -0
  14. package/dist/.opencode/plugins/foundry-tools/memory-admin-tools.js +296 -0
  15. package/dist/.opencode/plugins/foundry-tools/memory-helpers.js +104 -0
  16. package/dist/.opencode/plugins/foundry-tools/memory-tools.js +286 -0
  17. package/dist/.opencode/plugins/foundry-tools/orchestrate-tool.js +159 -0
  18. package/dist/.opencode/plugins/foundry-tools/snapshot-tools.js +104 -0
  19. package/dist/.opencode/plugins/foundry-tools/stage-tools.js +186 -0
  20. package/dist/.opencode/plugins/foundry-tools/validate-tools.js +263 -0
  21. package/dist/.opencode/plugins/foundry-tools/workfile-tools.js +102 -0
  22. package/dist/.opencode/plugins/foundry.js +105 -0
  23. package/dist/CHANGELOG.md +533 -0
  24. package/dist/LICENSE +21 -0
  25. package/dist/README.md +278 -0
  26. package/dist/docs/README.md +59 -0
  27. package/dist/docs/architecture.md +433 -0
  28. package/dist/docs/concepts.md +395 -0
  29. package/dist/docs/getting-started.md +344 -0
  30. package/dist/docs/memory-maintenance.md +176 -0
  31. package/dist/docs/tools.md +1411 -0
  32. package/dist/docs/work-spec.md +283 -0
  33. package/dist/scripts/lib/artefacts.js +151 -0
  34. package/dist/scripts/lib/assay/loader.js +151 -0
  35. package/dist/scripts/lib/assay/parse-jsonl.js +102 -0
  36. package/dist/scripts/lib/assay/permissions.js +52 -0
  37. package/dist/scripts/lib/assay/run.js +219 -0
  38. package/dist/scripts/lib/assay/spawn-with-timeout.js +138 -0
  39. package/dist/scripts/lib/attestation/attest.js +111 -0
  40. package/dist/scripts/lib/attestation/canonical-json.js +109 -0
  41. package/dist/scripts/lib/attestation/hash.js +17 -0
  42. package/dist/scripts/lib/attestation/parse.js +14 -0
  43. package/dist/scripts/lib/attestation/payload.js +106 -0
  44. package/dist/scripts/lib/attestation/render.js +16 -0
  45. package/dist/scripts/lib/attestation/verify.js +15 -0
  46. package/dist/scripts/lib/branch-guard.js +72 -0
  47. package/dist/scripts/lib/config-creators/appraiser.js +9 -0
  48. package/dist/scripts/lib/config-creators/artefact-type.js +9 -0
  49. package/dist/scripts/lib/config-creators/cycle.js +11 -0
  50. package/dist/scripts/lib/config-creators/factory.js +49 -0
  51. package/dist/scripts/lib/config-creators/flow.js +11 -0
  52. package/dist/scripts/lib/config-validators/appraiser.js +49 -0
  53. package/dist/scripts/lib/config-validators/artefact-type.js +38 -0
  54. package/dist/scripts/lib/config-validators/cycle.js +131 -0
  55. package/dist/scripts/lib/config-validators/flow.js +57 -0
  56. package/dist/scripts/lib/config-validators/helpers.js +96 -0
  57. package/dist/scripts/lib/config-validators/law.js +96 -0
  58. package/dist/scripts/lib/config.js +328 -0
  59. package/dist/scripts/lib/failed-flow.js +131 -0
  60. package/dist/scripts/lib/feedback-store.js +249 -0
  61. package/dist/scripts/lib/feedback-transitions.js +105 -0
  62. package/dist/scripts/lib/finalize.js +70 -0
  63. package/dist/scripts/lib/foundational-guards.js +13 -0
  64. package/dist/scripts/lib/git-bridge.js +77 -0
  65. package/dist/scripts/lib/git-finish/work-finish.js +233 -0
  66. package/dist/scripts/lib/git-policy.js +101 -0
  67. package/dist/scripts/lib/guards.js +125 -0
  68. package/dist/scripts/lib/history.js +132 -0
  69. package/dist/scripts/lib/memory/admin/create-edge-type.js +91 -0
  70. package/dist/scripts/lib/memory/admin/create-entity-type.js +43 -0
  71. package/dist/scripts/lib/memory/admin/create-extractor.js +67 -0
  72. package/dist/scripts/lib/memory/admin/drop-edge-type.js +40 -0
  73. package/dist/scripts/lib/memory/admin/drop-entity-type.js +172 -0
  74. package/dist/scripts/lib/memory/admin/dump.js +47 -0
  75. package/dist/scripts/lib/memory/admin/helpers.js +31 -0
  76. package/dist/scripts/lib/memory/admin/init.js +170 -0
  77. package/dist/scripts/lib/memory/admin/live-store.js +76 -0
  78. package/dist/scripts/lib/memory/admin/reembed.js +285 -0
  79. package/dist/scripts/lib/memory/admin/rename-edge-type.js +54 -0
  80. package/dist/scripts/lib/memory/admin/rename-entity-type.js +151 -0
  81. package/dist/scripts/lib/memory/admin/reset.js +24 -0
  82. package/dist/scripts/lib/memory/admin/vacuum.js +9 -0
  83. package/dist/scripts/lib/memory/admin/validate.js +19 -0
  84. package/dist/scripts/lib/memory/config.js +149 -0
  85. package/dist/scripts/lib/memory/cozo.js +136 -0
  86. package/dist/scripts/lib/memory/drift.js +71 -0
  87. package/dist/scripts/lib/memory/embeddings.js +128 -0
  88. package/dist/scripts/lib/memory/frontmatter.js +75 -0
  89. package/dist/scripts/lib/memory/ndjson.js +84 -0
  90. package/dist/scripts/lib/memory/paths.js +25 -0
  91. package/dist/scripts/lib/memory/permissions.js +41 -0
  92. package/dist/scripts/lib/memory/prompt.js +109 -0
  93. package/dist/scripts/lib/memory/query.js +56 -0
  94. package/dist/scripts/lib/memory/reads.js +109 -0
  95. package/dist/scripts/lib/memory/schema.js +64 -0
  96. package/dist/scripts/lib/memory/search.js +73 -0
  97. package/dist/scripts/lib/memory/singleton.js +49 -0
  98. package/dist/scripts/lib/memory/store.js +162 -0
  99. package/dist/scripts/lib/memory/types.js +93 -0
  100. package/dist/scripts/lib/memory/validate.js +58 -0
  101. package/dist/scripts/lib/memory/writes.js +40 -0
  102. package/{scripts → dist/scripts}/lib/pending.js +7 -2
  103. package/dist/scripts/lib/secret.js +59 -0
  104. package/{scripts → dist/scripts}/lib/slug.js +3 -2
  105. package/dist/scripts/lib/snapshot/finish.js +103 -0
  106. package/dist/scripts/lib/snapshot/inspect.js +253 -0
  107. package/dist/scripts/lib/snapshot/render.js +55 -0
  108. package/dist/scripts/lib/sort-fs-check.js +121 -0
  109. package/dist/scripts/lib/sort-routing.js +101 -0
  110. package/{scripts → dist/scripts}/lib/stage-guard.js +12 -6
  111. package/{scripts → dist/scripts}/lib/state.js +4 -0
  112. package/dist/scripts/lib/token.js +57 -0
  113. package/dist/scripts/lib/tracing.js +59 -0
  114. package/dist/scripts/lib/ulid.js +100 -0
  115. package/dist/scripts/lib/validator-jsonl.js +162 -0
  116. package/{scripts → dist/scripts}/lib/workfile.js +38 -20
  117. package/dist/scripts/orchestrate-cycle.js +215 -0
  118. package/dist/scripts/orchestrate-phases.js +314 -0
  119. package/dist/scripts/orchestrate.js +163 -0
  120. package/dist/scripts/sort.js +278 -0
  121. package/{skills → dist/skills}/add-appraiser/SKILL.md +39 -9
  122. package/{skills → dist/skills}/add-artefact-type/SKILL.md +62 -40
  123. package/{skills → dist/skills}/add-cycle/SKILL.md +57 -17
  124. package/dist/skills/add-extractor/SKILL.md +133 -0
  125. package/{skills → dist/skills}/add-flow/SKILL.md +36 -10
  126. package/dist/skills/add-law/SKILL.md +191 -0
  127. package/dist/skills/add-memory-edge-type/SKILL.md +52 -0
  128. package/dist/skills/add-memory-entity-type/SKILL.md +74 -0
  129. package/{skills → dist/skills}/appraise/SKILL.md +62 -13
  130. package/dist/skills/assay/SKILL.md +72 -0
  131. package/dist/skills/change-embedding-model/SKILL.md +58 -0
  132. package/dist/skills/drop-memory-edge-type/SKILL.md +54 -0
  133. package/dist/skills/drop-memory-entity-type/SKILL.md +57 -0
  134. package/dist/skills/dry-run/SKILL.md +116 -0
  135. package/{skills → dist/skills}/flow/SKILL.md +15 -2
  136. package/dist/skills/forge/SKILL.md +121 -0
  137. package/dist/skills/human-appraise/SKILL.md +153 -0
  138. package/{skills → dist/skills}/init-foundry/SKILL.md +23 -4
  139. package/dist/skills/init-memory/SKILL.md +92 -0
  140. package/{skills → dist/skills}/orchestrate/SKILL.md +30 -4
  141. package/dist/skills/quench/SKILL.md +99 -0
  142. package/{skills → dist/skills}/refresh-agents/SKILL.md +1 -1
  143. package/dist/skills/rename-memory-edge-type/SKILL.md +50 -0
  144. package/dist/skills/rename-memory-entity-type/SKILL.md +51 -0
  145. package/dist/skills/reset-memory/SKILL.md +54 -0
  146. package/dist/skills/upgrade-foundry/SKILL.md +191 -0
  147. package/package.json +34 -17
  148. package/.opencode/plugins/foundry.js +0 -761
  149. package/CHANGELOG.md +0 -100
  150. package/docs/concepts.md +0 -122
  151. package/docs/getting-started.md +0 -187
  152. package/docs/work-spec.md +0 -207
  153. package/scripts/lib/artefacts.js +0 -124
  154. package/scripts/lib/config.js +0 -175
  155. package/scripts/lib/feedback-transitions.js +0 -25
  156. package/scripts/lib/feedback.js +0 -440
  157. package/scripts/lib/finalize.js +0 -41
  158. package/scripts/lib/history.js +0 -59
  159. package/scripts/lib/secret.js +0 -23
  160. package/scripts/lib/tags.js +0 -108
  161. package/scripts/lib/token.js +0 -26
  162. package/scripts/orchestrate.js +0 -418
  163. package/scripts/sort.js +0 -370
  164. package/scripts/validate-tags.js +0 -54
  165. package/skills/add-law/SKILL.md +0 -111
  166. package/skills/forge/SKILL.md +0 -88
  167. package/skills/human-appraise/SKILL.md +0 -82
  168. package/skills/quench/SKILL.md +0 -62
  169. package/skills/upgrade-foundry/SKILL.md +0 -216
  170. /package/{skills → dist/skills}/list-agents/SKILL.md +0 -0
@@ -0,0 +1,153 @@
1
+ ---
2
+ name: human-appraise
3
+ type: atomic
4
+ description: Human quality gate. Presents the artefact to the human for review and collects feedback tagged `human`.
5
+ ---
6
+
7
+ # Human Appraise
8
+
9
+ You are a human quality gate. Sort has routed to you either because the LLM appraisers have finished (normal flow) or because a deadlock was detected between forge and appraisers.
10
+
11
+ ## Prerequisites
12
+
13
+ Before running this skill, verify that the `foundry/` directory exists in the project root. If it does not exist, stop and tell the user:
14
+
15
+ > Foundry is not initialized in this project. Run the `init-foundry` skill first to create the foundry/ directory structure.
16
+
17
+ ## Stage lifecycle (mandatory)
18
+
19
+ Human-appraise runs inside an enforced stage. Your **first** and **last** tool calls are fixed:
20
+
21
+ 1. **First:** `foundry_stage_begin({stage, cycle, token})` — copy the token verbatim from the dispatch prompt.
22
+ 2. **Last:** `foundry_stage_end({summary})`.
23
+
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
+
26
+ Human-appraise **cannot** call `foundry_feedback_action`, `foundry_feedback_wontfix`, or `foundry_artefacts_set_status` — the tools reject those calls during a human-appraise stage (action/wontfix are forge-only forward transitions; set-status requires no active stage). See "Feedback handling" below for the legal transitions available to human-appraise.
27
+
28
+ ## Input
29
+
30
+ When invoked from orchestrate, you receive `{cycle, token, context}`:
31
+ - `cycle` — the current cycle id
32
+ - `token` — single-use token for `foundry_stage_begin`
33
+ - `context.artefact_file` — the target artefact
34
+ - `context.recent_feedback` — recent deadlocked feedback items to present to the user
35
+
36
+ Your FIRST tool call must be `foundry_stage_begin({stage: 'human-appraise:<cycle>', cycle, token})`.
37
+
38
+ Your LAST tool call must be `foundry_stage_end({summary: '<one-sentence description of the user verdict>'})` — orchestrate reads this summary for the commit message.
39
+
40
+ ## Protocol
41
+
42
+ 1. `foundry_stage_begin(...)`.
43
+ 2. Gather context by calling:
44
+ - `foundry_workfile_get` — current state, goal, cycle
45
+
46
+ **Check for failed flow state.** If `foundry_workfile_get` returns `{status: "failed", reason: ...}`, STOP. Do not do any substantive work. Tell the user:
47
+
48
+ > The flow is in a failed state. Reason: `<reason>`.
49
+ >
50
+ > No further work is permitted. To recover:
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.
55
+
56
+ Then call `foundry_stage_end({summary: 'Flow is failed; no human appraisal performed'})`, return control to the user, and stop.
57
+ - `foundry_artefacts_list({cycle: <current-cycle>})` — this cycle's artefact files and status (always pass the `cycle` filter; omitting it returns stale rows from prior sessions)
58
+ - `foundry_feedback_list` — all existing feedback
59
+ - `foundry_history_list({cycle: <current-cycle>})` — what has happened so far
60
+
61
+ 3. Read the artefact file(s) for this cycle.
62
+
63
+ 4. Present to the human:
64
+ - The current artefact content (full file content or multi-file diff)
65
+ - A summary of this iteration's feedback (resolved and open)
66
+ - If this is a deadlock escalation, clearly explain the deadlock:
67
+ - Which feedback item(s) are stuck
68
+ - The appraiser's reasoning
69
+ - Forge's wont-fix or revision justification
70
+ - Ask the human to resolve the disagreement
71
+
72
+ 5. Wait for the human's response.
73
+
74
+ 6. Act on the response (tag MUST be `human` on any added feedback — the tool rejects other tags during human-appraise):
75
+ - **Approve** — "looks good" / "continue" — no feedback added, sort will advance.
76
+ - **Provide feedback** — `foundry_feedback_add({ file, text, tag: 'human' })`. Sort will route back to forge.
77
+ - **Resolve feedback** — `foundry_feedback_resolve({ id, resolution, reason? })` for items in `{actioned, wont-fix, deadlocked}`. See "Feedback handling" below for the legal transitions and authority rules.
78
+ - **Abort** — human-appraise cannot directly mark the artefact `blocked` (the `foundry_artefacts_set_status` tool refuses calls during an active stage). 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 marks the artefact blocked on its own.
79
+
80
+ 7. `foundry_stage_end({summary})` — describe what the human decided so sort can log it.
81
+
82
+ ## Feedback handling
83
+
84
+ As a human-appraise stage, you can add human feedback and resolve feedback
85
+ items (including deadlock overrides). **Human-appraise can resolve any
86
+ non-resolved source-stage item regardless of source** — this is the
87
+ universal override authority recorded in spec §5.1 rule 5. It is not
88
+ limited to deadlocked items, though in practice most overrides today are
89
+ on deadlocked items because default sort routing only surfaces deadlocked
90
+ items to human-appraise (see §17 future-work note below).
91
+
92
+ What human-appraise can NOT do:
93
+
94
+ - **No forward transitions.** `foundry_feedback_action` and
95
+ `foundry_feedback_wontfix` move items from `{open, rejected}` to
96
+ `{actioned, wont-fix}` — that is forge's lane (spec §5.1 rule 1) and
97
+ the tools reject calls from any non-forge stage. If an open or rejected
98
+ item needs work, sort will route to forge after this stage ends.
99
+ - **No artefact status writes.** `foundry_artefacts_set_status` requires
100
+ no active stage; it refuses calls while human-appraise is open. Status
101
+ promotion to `done`/`blocked` is owned by sort/orchestrate based on
102
+ routing.
103
+
104
+ What human-appraise CAN do:
105
+
106
+ 1. **Add new human feedback.** Call `foundry_feedback_add` with
107
+ `{ file, text, tag: 'human' }`. The `source` is your stage id. The tool
108
+ returns `{ ok: true, id, deduped }`; `deduped: true` indicates an
109
+ existing non-resolved item with the same `(file, tag, hash(text))` was
110
+ found and no new snapshot was written, `deduped: false` indicates a new
111
+ item was created.
112
+
113
+ 2. **Resolve any non-resolved source-stage item.** For items in
114
+ `{actioned, wont-fix}` (sourced from quench, appraise, or
115
+ human-appraise), call `foundry_feedback_resolve` with
116
+ `{ id, resolution: 'approved' | 'rejected', reason? }`. Human-appraise
117
+ may resolve any such item regardless of source, including items from
118
+ other stage ids.
119
+
120
+ 3. **Resolve deadlocked items.** When items reach `state: deadlocked`
121
+ (written by sort when an item's history depth hits
122
+ `deadlock-iterations`), human-appraise is the ONLY stage authorised
123
+ to resolve them. Call `foundry_feedback_resolve` with
124
+ `{ id, resolution: 'approved' | 'rejected', reason: '...' }`.
125
+ `reason` is always required on deadlock override — it documents why
126
+ the deadlock is being broken. After human-appraise resolves every
127
+ deadlocked item, the cycle resumes normal forge/appraise routing. If
128
+ deadlocks remain after human-appraise, the cycle blocks (per spec §5.2).
129
+
130
+ **Reason rules.** `reason` is required when rejecting feedback
131
+ (`resolution: 'rejected'`) and when overriding a deadlocked item.
132
+ Non-deadlocked approved resolution via
133
+ `foundry_feedback_resolve({ id, resolution: 'approved', reason? })` may
134
+ omit `reason`; deadlock override always requires `reason` to document why
135
+ the deadlock is being broken.
136
+
137
+ **Future work.** Spec §17 notes that a cycle-level mode flag letting
138
+ human-appraise see all unresolved feedback (not just deadlocked items)
139
+ before sort routes is planned for a future release. In v2.6.0 the
140
+ authority is universal but reachability is limited — you typically only
141
+ see deadlocked items on the route from sort. If you do see non-deadlocked
142
+ items (e.g. you were invoked directly by the user), the same authority
143
+ applies.
144
+
145
+ ## What you do NOT do
146
+
147
+ - You do not write files — all output goes through foundry tools.
148
+ - You do not make decisions for the human — present the state and wait.
149
+ - You do not modify the artefact.
150
+ - You do not skip the pause — the human must respond before continuing.
151
+ - You do not filter or summarise away important details — show the full picture.
152
+ - You do not call `foundry_history_append` or `foundry_git_commit` — `foundry_orchestrate` owns those (the tools are not registered publicly).
153
+ - You do not register artefacts — handled by `foundry_stage_end({summary})`.
@@ -29,23 +29,35 @@ Set up the `foundry/` directory structure in the current project.
29
29
  appraisers/.gitkeep
30
30
  ```
31
31
 
32
- 3. **Generate foundry agent files**
32
+ 3. **Update `.gitignore`**
33
+
34
+ Append `.snapshots/` to the project's `.gitignore` (creating the file if absent). This directory is where dry-run snapshots are written and must never be committed.
35
+
36
+ The plugin will idempotently append `.foundry/` itself on first boot, so you do not need to add that line.
37
+
38
+ 4. **Generate foundry agent files**
33
39
 
34
40
  Run the `refresh-agents` skill to generate `.opencode/agents/foundry-*.md` files for multi-model routing.
35
41
 
36
- 4. **Commit the structure**
42
+ 5. **Commit the structure**
37
43
 
38
44
  ```bash
39
- git add foundry/ .opencode/agents/foundry-*.md
45
+ git add foundry/ .gitignore .opencode/agents/foundry-*.md
40
46
  git commit -m "feat: initialize Foundry project structure"
41
47
  ```
42
48
 
43
- 5. **Guide next steps**
49
+ 6. **Guide next steps**
44
50
 
45
51
  Tell the user:
46
52
 
47
53
  > Foundry is initialized. **Restart OpenCode** for the new foundry agents to take effect.
48
54
  >
55
+ > The first time the plugin boots in this project, it will create the
56
+ > `.foundry/` runtime directory (which holds the per-worktree HMAC key) and
57
+ > idempotently append `.foundry/` to your `.gitignore` so the secret never
58
+ > gets committed. The `.snapshots/` line was added by this skill to keep
59
+ > dry-run snapshots out of git.
60
+ >
49
61
  > Here's how to set up your first pipeline:
50
62
  >
51
63
  > 1. **Define an artefact type** — use the `add-artefact-type` skill
@@ -55,3 +67,10 @@ Set up the `foundry/` directory structure in the current project.
55
67
  > 5. **Create a flow** — use the `add-flow` skill
56
68
  >
57
69
  > Then run your flow with the `flow` skill.
70
+ >
71
+ > **Optional: Flow Memory**
72
+ >
73
+ > If your flows need persistent knowledge (entities, relationships, semantic
74
+ > search), use the `init-memory` skill to scaffold flow memory. Memory is
75
+ > useful for projects that need to track code structure, dependencies, or
76
+ > domain knowledge across flow runs.
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: init-memory
3
+ type: atomic
4
+ description: Initialize flow memory by creating the foundry/memory/ and foundry-memory/ directory structures
5
+ ---
6
+
7
+ # Initialize Flow Memory
8
+
9
+ Scaffold `foundry/memory/` (config) and `foundry-memory/relations/` (row data)
10
+ in the current project. `foundry/memory/` holds entity-type and edge-type
11
+ definitions, the schema, the config, and the gitignored Cozo database.
12
+ `foundry-memory/relations/` is a top-level sibling of `foundry/` that holds
13
+ the committed NDJSON relations.
14
+
15
+ ## Prerequisites
16
+
17
+ Before running this skill, verify all of the following:
18
+
19
+ 1. The `foundry/` directory exists in the project root. If it does not
20
+ exist, stop and tell the user:
21
+
22
+ > Foundry is not initialized in this project. Run the
23
+ > `init-foundry` skill first to create the foundry/ directory
24
+ > structure.
25
+
26
+ 2. The current git branch is a `config/*` branch. Run
27
+ `git rev-parse --abbrev-ref HEAD` and confirm it matches
28
+ `config/<description>`.
29
+
30
+ 3. If the branch does not start with `config/`, instruct the user to
31
+ create one before continuing:
32
+
33
+ > Foundry configuration changes must be made on a config/* branch.
34
+ > From a clean main branch, call:
35
+ >
36
+ > `foundry_git_branch({ kind: "config", description: "<short-name>" })`
37
+ >
38
+ > Then re-run this skill.
39
+
40
+ If the user is on a `dry-run/*/*` branch, they must finish
41
+ that dry-run first (`foundry_git_finish({ message, confirm: true })`)
42
+ before re-running this skill on the parent `config/*`.
43
+
44
+ Neither `foundry/memory/` nor `foundry-memory/` may already exist.
45
+
46
+ ## Steps
47
+
48
+ 1. **Ask the user** whether to enable embeddings (semantic search).
49
+ - Default: **yes**, targeting a local Ollama instance
50
+ (`http://localhost:11434/v1`, `nomic-embed-text`, 768 dims).
51
+ - If the user declines, note it and pass `embeddings_enabled: false` in
52
+ step 2.
53
+
54
+ 2. **Invoke `foundry_memory_init`** with `{ embeddings_enabled, probe: true }`.
55
+
56
+ The tool deterministically:
57
+ - creates `foundry/memory/entities/` and `foundry/memory/edges/` with `.gitkeep`,
58
+ - creates `foundry-memory/relations/` (top-level sibling of `foundry/`) with `.gitkeep`,
59
+ - writes `foundry/memory/config.md` (frontmatter set from the embeddings choice),
60
+ - writes `foundry/memory/schema.json` (`embeddings: {...}` when enabled, `null` when not),
61
+ - appends the three `foundry/memory/memory.db*` entries to `.gitignore`
62
+ idempotently,
63
+ - probes the embedding provider (only when enabled) and returns the result.
64
+
65
+ It fails if either `foundry/memory/` or `foundry-memory/` already exists.
66
+
67
+ 3. **Handle the probe result** (field `probe` in the return value).
68
+ - `probe == null`: embeddings disabled, skip.
69
+ - `probe.ok == true`: display `✓ Embedding provider responded (dimensions: N)`
70
+ where N is `probe.dimensions`, then continue.
71
+ - `probe.ok == false`: present the user with these options:
72
+ 1. Install/start Ollama and `ollama pull nomic-embed-text`, then invoke
73
+ `foundry_memory_validate` to re-check.
74
+ 2. Edit `foundry/memory/config.md` frontmatter to point at a different
75
+ OpenAI-compatible endpoint, then invoke `foundry_memory_validate`.
76
+ 3. Set `embeddings.enabled: false` in `foundry/memory/config.md`.
77
+
78
+ 4. **Commit the scaffold**:
79
+
80
+ ```bash
81
+ git add foundry/memory/ foundry-memory/ .gitignore
82
+ git commit -m "feat: initialise flow memory"
83
+ ```
84
+
85
+ 5. **Tell the user what is next**:
86
+
87
+ > Flow memory is scaffolded. Next steps:
88
+ >
89
+ > - Use `add-memory-entity-type` to declare entity types (e.g. `class`,
90
+ > `method`, `table`).
91
+ > - Use `add-memory-edge-type` to declare edge types (e.g. `calls`,
92
+ > `writes`, `references`).
@@ -11,11 +11,25 @@ You drive a foundry cycle by calling `foundry_orchestrate` repeatedly and acting
11
11
 
12
12
  Before running this skill, verify that `foundry/` exists in the project root and `WORK.md` has been created by the flow skill (with `flow`, `cycle`, and `goal` fields). If not, stop and tell the user to run the flow skill first.
13
13
 
14
+ ### Check for failed flow state
15
+
16
+ Before iterating, call `foundry_workfile_get` once. If it returns `{status: "failed", reason: ...}`, STOP. Do not call any other tool. Tell the user:
17
+
18
+ > The flow is in a failed state. Reason: `<reason>`.
19
+ >
20
+ > No further work is permitted. To recover:
21
+ >
22
+ > 1. `foundry_workfile_delete({confirm: true})` to abandon the cycle.
23
+ > 2. Back out to main (`git checkout main`) and delete the work branch.
24
+ > 3. Investigate and fix the root cause of the failure before restarting.
25
+
26
+ Then return control to the user and stop.
27
+
14
28
  ## Protocol
15
29
 
16
30
  Loop until `foundry_orchestrate` returns a terminal action (`done`, `blocked`, or `violation`):
17
31
 
18
- 1. Call `foundry_orchestrate({lastResult})`. Omit `lastResult` on the first iteration. On subsequent iterations, pass `{kind, ok}` reflecting the previous action's outcome.
32
+ 1. Call `foundry_orchestrate({lastResult})`. Omit `lastResult` on the first iteration. On subsequent iterations, pass `{ok, error?}` reflecting the previous action's outcome.
19
33
 
20
34
  2. Switch on the returned `action`:
21
35
 
@@ -31,7 +45,7 @@ task tool:
31
45
  prompt: <prompt-from-payload — pass verbatim>
32
46
  ```
33
47
 
34
- When the task returns, call `foundry_orchestrate({lastResult: {kind: 'dispatch', ok: true}})`. If the task tool itself errored or reported a subagent crash, pass `{kind: 'dispatch', ok: false, error: '<message>'}`.
48
+ When the task returns, call `foundry_orchestrate({lastResult: {ok: true}})`. If the task tool itself errored or reported a subagent crash, pass `{ok: false, error: '<message>'}`.
35
49
 
36
50
  ### `human_appraise`
37
51
 
@@ -39,7 +53,7 @@ Payload: `{stage, token, context}`.
39
53
 
40
54
  Invoke the `human-appraise` skill inline, passing `{cycle, token, context}`. The skill will prompt the user, collect feedback, and call `foundry_stage_end({summary})`.
41
55
 
42
- When it returns, call `foundry_orchestrate({lastResult: {kind: 'human_appraise', ok: true}})`.
56
+ When it returns, call `foundry_orchestrate({lastResult: {ok: true}})`.
43
57
 
44
58
  ### `done`
45
59
 
@@ -65,5 +79,17 @@ Report to the user: "Cycle halted (violation): `<details>`. Affected files: `<af
65
79
 
66
80
  - You do NOT inline forge / quench / appraise work. Always dispatch via `task`.
67
81
  - You do NOT mint, modify, or cache tokens. The `prompt` from orchestrate already contains the token verbatim.
68
- - You do NOT call `foundry_history_append`, `foundry_git_commit`, `foundry_stage_finalize`, or `foundry_sort`. These are not registered tools in v2.3+; orchestrate handles them internally.
82
+ - `foundry_history_append`, `foundry_git_commit`, `foundry_stage_finalize`, and `foundry_sort` are not registered tools; orchestrate handles them internally via the loop.
69
83
  - You do NOT reorder the protocol. `foundry_orchestrate` returns, you act, you call back. Nothing else between.
84
+
85
+ ## Feedback visibility
86
+
87
+ Orchestrate's loop does not read, parse, or write feedback directly.
88
+ Subagents invoked via `dispatch` use the `foundry_feedback_list` /
89
+ `foundry_feedback_add` / `foundry_feedback_action` / `foundry_feedback_wontfix`
90
+ / `foundry_feedback_resolve` tools themselves; orchestrate does not stage
91
+ feedback state between iterations. If you want to inspect feedback state
92
+ between iterations for diagnostic purposes, call `foundry_feedback_list` —
93
+ the response shape is `[{ id, file, tag, text, source, state, depth,
94
+ reason? }]`. This is read-only and does not affect the loop's dispatch
95
+ decisions.
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: quench
3
+ type: atomic
4
+ description: Deterministic validation of an artefact by running CLI commands. Writes feedback via foundry tools.
5
+ ---
6
+
7
+ # Quench
8
+
9
+ You run deterministic checks on an artefact by executing the CLI commands defined in the law-based validators for the artefact's type. No judgment — commands pass or fail.
10
+
11
+ ## Prerequisites
12
+
13
+ Before running this skill, verify that the `foundry/` directory exists in the project root. If it does not exist, stop and tell the user:
14
+
15
+ > Foundry is not initialized in this project. Run the `init-foundry` skill first to create the foundry/ directory structure.
16
+
17
+ ## Stage lifecycle (mandatory)
18
+
19
+ Quench runs inside an enforced stage. Your **first** and **last** tool calls are fixed:
20
+
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({summary})`.
23
+
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
+
26
+ ## Protocol
27
+
28
+ 1. `foundry_stage_begin(...)`.
29
+ 2. `foundry_workfile_get` — read the `cycle` from frontmatter.
30
+
31
+ **Check for failed flow state.** If `foundry_workfile_get` returns `{status: "failed", reason: ...}`, STOP. Do not call any other tool. Tell the user:
32
+
33
+ > The flow is in a failed state. Reason: `<reason>`.
34
+ >
35
+ > No further work is permitted. To recover:
36
+ >
37
+ > 1. `foundry_workfile_delete({confirm: true})` to abandon the cycle.
38
+ > 2. Back out to main (`git checkout main`) and delete the work branch.
39
+ > 3. Investigate and fix the root cause of the failure before restarting.
40
+
41
+ Then return control to the user and stop.
42
+ 3. `foundry_artefacts_list({cycle: <current-cycle>})` — enumerate the artefacts produced by **this** cycle. Always pass the `cycle` filter; omitting it returns rows from prior sessions and validates stale files. Skip rows whose status is `done` or `blocked`.
43
+ 4. For each remaining row:
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
+ 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 via `foundry_stage_end` summary; do not convert them to law-tagged feedback.
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
+ 6. If every command passes for every row, add no new feedback.
49
+ 7. If the artefact table has no rows for this cycle, `foundry_stage_end({summary: 'SKIP: no artefacts registered for this cycle'})` and stop.
50
+ 8. `foundry_stage_end({summary})`.
51
+
52
+ ## Feedback handling
53
+
54
+ As a quench stage, you have two feedback responsibilities:
55
+
56
+ 1. **Adding new validation feedback.** For each entry returned in the `items`
57
+ array from `foundry_validate_run`, call `foundry_feedback_add` with
58
+ `{ file: item.file, text: item.text, tag: 'law:' + item.lawId + ':' + item.validatorId }`.
59
+ The `source` is automatically recorded as your stage id. Feedback tags must
60
+ follow the `law:<law-id>:<validator-id>` format to identify which law and
61
+ which validator on that law produced the feedback.
62
+
63
+ The tool returns `{ ok: true, id, deduped }` on success. `deduped: true`
64
+ means an existing non-resolved item with the same `(file, tag,
65
+ hash(text))` was found; the returned `id` is the existing item's id and
66
+ no new snapshot was written. `deduped: false` means a new item was
67
+ created. Either way, `id` is usable for follow-up calls.
68
+
69
+ 2. **Resolving items you sourced.** Call `foundry_feedback_list` to see items
70
+ whose `source` matches your stage id. For items whose current state is
71
+ `actioned` or `wont-fix`, use deterministic validation results to decide
72
+ whether the issue is gone:
73
+ - Validation now passes / issue is gone: call `foundry_feedback_resolve` with `{ id, resolution: 'approved' }`.
74
+ `reason` is optional here.
75
+ - Validation still fails / issue remains: call `foundry_feedback_resolve` with `{ id, resolution: 'rejected', reason: '...' }`.
76
+ `reason` is required on `rejected`. Forge will see the item back in
77
+ the `rejected` state on the next pass.
78
+
79
+ **Reason rules.** `reason` is required when resolving a deadlocked item
80
+ (deadlock override — but quench never does this; only human-appraise does),
81
+ or when `resolution: 'rejected'`. On `resolution: 'approved'` for a
82
+ non-deadlocked item, `reason` is optional.
83
+
84
+ You cannot resolve items sourced by other stages, and you cannot touch
85
+ deadlocked items (only human-appraise can override those).
86
+
87
+ ## History
88
+
89
+ Do NOT call `foundry_history_append` or `foundry_git_commit` — `foundry_orchestrate` handles those (the tools are not registered publicly). Return a clear summary via `foundry_stage_end` (e.g., "2 validation issues found" or "Validation passed").
90
+
91
+ ## What you do NOT do
92
+
93
+ - You do not write files — all output goes through `foundry_feedback_add`.
94
+ - You do not make subjective judgments.
95
+ - You do not revise the artefact (forge's job).
96
+ - You do not evaluate laws — that is the appraise skill's job.
97
+ - You do not invent validation rules — you only run commands from the law validators.
98
+ - You do not duplicate feedback that already exists (the tool de-duplicates by text-hash, but don't rely on it).
99
+ - You do not register artefacts — that happens automatically.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: refresh-agents
3
- description: Use when initializing Foundry or after adding/removing providers to regenerate foundry-* agent files for multi-model routing.
3
+ description: Use when initialising Foundry or after adding/removing providers to regenerate foundry-* agent files for multi-model routing.
4
4
  ---
5
5
 
6
6
  # Refresh Agents
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: rename-memory-edge-type
3
+ type: atomic
4
+ description: Rename an edge type (does not touch row data)
5
+ ---
6
+
7
+ # Rename Memory Edge Type
8
+
9
+ ## Prerequisites
10
+
11
+ Before running this skill, verify all of the following:
12
+
13
+ 1. The `foundry/` directory exists in the project root. If it does not
14
+ exist, stop and tell the user:
15
+
16
+ > Foundry is not initialized in this project. Run the
17
+ > `init-foundry` skill first to create the foundry/ directory
18
+ > structure.
19
+
20
+ 2. The current git branch is a `config/*` branch. Run
21
+ `git rev-parse --abbrev-ref HEAD` and confirm it matches
22
+ `config/<description>`.
23
+
24
+ 3. If the branch does not start with `config/`, instruct the user to
25
+ create one before continuing:
26
+
27
+ > Foundry configuration changes must be made on a config/* branch.
28
+ > From a clean main branch, call:
29
+ >
30
+ > `foundry_git_branch({ kind: "config", description: "<short-name>" })`
31
+ >
32
+ > Then re-run this skill.
33
+
34
+ If the user is on a `dry-run/*/*` branch, they must finish
35
+ that dry-run first (`foundry_git_finish({ message, confirm: true })`)
36
+ before re-running this skill on the parent `config/*`.
37
+
38
+ 4. Memory is initialised. The `from` edge type must exist; the `to`
39
+ name must be free.
40
+
41
+ ## Steps
42
+
43
+ 1. Ask the user for `from` and `to`.
44
+ 2. Invoke `foundry_memory_rename_edge_type` with `{ from, to }`.
45
+ 3. Commit:
46
+
47
+ ```bash
48
+ git add -A foundry/memory/ foundry-memory/relations/
49
+ git commit -m "refactor(memory): rename edge type <from> -> <to>"
50
+ ```
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: rename-memory-entity-type
3
+ type: atomic
4
+ description: Rename an entity type and migrate all referring edges and rows
5
+ ---
6
+
7
+ # Rename Memory Entity Type
8
+
9
+ ## Prerequisites
10
+
11
+ Before running this skill, verify all of the following:
12
+
13
+ 1. The `foundry/` directory exists in the project root. If it does not
14
+ exist, stop and tell the user:
15
+
16
+ > Foundry is not initialized in this project. Run the
17
+ > `init-foundry` skill first to create the foundry/ directory
18
+ > structure.
19
+
20
+ 2. The current git branch is a `config/*` branch. Run
21
+ `git rev-parse --abbrev-ref HEAD` and confirm it matches
22
+ `config/<description>`.
23
+
24
+ 3. If the branch does not start with `config/`, instruct the user to
25
+ create one before continuing:
26
+
27
+ > Foundry configuration changes must be made on a config/* branch.
28
+ > From a clean main branch, call:
29
+ >
30
+ > `foundry_git_branch({ kind: "config", description: "<short-name>" })`
31
+ >
32
+ > Then re-run this skill.
33
+
34
+ If the user is on a `dry-run/*/*` branch, they must finish
35
+ that dry-run first (`foundry_git_finish({ message, confirm: true })`)
36
+ before re-running this skill on the parent `config/*`.
37
+
38
+ 4. Memory is initialised. The `from` entity type must exist; the `to`
39
+ name must be free (no existing entity or edge).
40
+
41
+ ## Steps
42
+
43
+ 1. Ask the user for `from` and `to`.
44
+ 2. Warn the user: this rewrites committed NDJSON rows in every edge that references the entity. Preview the change with `foundry_memory_validate` if desired.
45
+ 3. Invoke `foundry_memory_rename_entity_type` with `{ from, to }`.
46
+ 4. Commit:
47
+
48
+ ```bash
49
+ git add -A foundry/memory/ foundry-memory/relations/
50
+ git commit -m "refactor(memory): rename entity type <from> -> <to>"
51
+ ```
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: reset-memory
3
+ type: atomic
4
+ description: Purge all memory data (entities and edges) while keeping type definitions
5
+ ---
6
+
7
+ # Reset Memory
8
+
9
+ **Destructive.** Empties every relation file and deletes the live `.db`. Type
10
+ definitions are preserved.
11
+
12
+ ## Prerequisites
13
+
14
+ Before running this skill, verify all of the following:
15
+
16
+ 1. The `foundry/` directory exists in the project root. If it does not
17
+ exist, stop and tell the user:
18
+
19
+ > Foundry is not initialized in this project. Run the
20
+ > `init-foundry` skill first to create the foundry/ directory
21
+ > structure.
22
+
23
+ 2. The current git branch is a `config/*` branch. Run
24
+ `git rev-parse --abbrev-ref HEAD` and confirm it matches
25
+ `config/<description>`.
26
+
27
+ 3. If the branch does not start with `config/`, instruct the user to
28
+ create one before continuing:
29
+
30
+ > Foundry configuration changes must be made on a config/* branch.
31
+ > From a clean main branch, call:
32
+ >
33
+ > `foundry_git_branch({ kind: "config", description: "<short-name>" })`
34
+ >
35
+ > Then re-run this skill.
36
+
37
+ If the user is on a `dry-run/*/*` branch, they must finish
38
+ that dry-run first (`foundry_git_finish({ message, confirm: true })`)
39
+ before re-running this skill on the parent `config/*`.
40
+
41
+ 4. Memory is initialised (`foundry/memory/` exists; run `init-memory`
42
+ if not).
43
+
44
+ ## Steps
45
+
46
+ 1. Warn the user of the scope.
47
+ 2. Require explicit confirmation.
48
+ 3. Invoke `foundry_memory_reset` with `{ confirm: true }`.
49
+ 4. Commit:
50
+
51
+ ```bash
52
+ git add foundry-memory/relations/ foundry/memory/schema.json
53
+ git commit -m "chore(memory): reset memory data"
54
+ ```