@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,133 @@
1
+ ---
2
+ name: add-extractor
3
+ type: atomic
4
+ description: Create a new extractor definition under foundry/memory/extractors/. An extractor is a project-authored CLI that emits JSONL describing entities and edges to upsert into flow memory.
5
+ ---
6
+
7
+ # Add Extractor
8
+
9
+ Use this skill to register a new extractor — a script that reads the codebase (via `tree-sitter`, `javap`, language servers, or whatever suits the project) and emits line-delimited JSON describing entities and edges to upsert into flow memory during an `assay` stage.
10
+
11
+ ## Prerequisites
12
+
13
+ Before running this skill, verify all of the following:
14
+
15
+ 1. The `foundry/` directory exists in the project root. If it does not
16
+ exist, stop and tell the user:
17
+
18
+ > Foundry is not initialized in this project. Run the
19
+ > `init-foundry` skill first to create the foundry/ directory
20
+ > structure.
21
+
22
+ 2. The current git branch is a `config/*` branch. Run
23
+ `git rev-parse --abbrev-ref HEAD` and confirm it matches
24
+ `config/<description>`.
25
+
26
+ 3. If the branch does not start with `config/`, instruct the user to
27
+ create one before continuing:
28
+
29
+ > Foundry configuration changes must be made on a config/* branch.
30
+ > From a clean main branch, call:
31
+ >
32
+ > `foundry_git_branch({ kind: "config", description: "<short-name>" })`
33
+ >
34
+ > Then re-run this skill.
35
+
36
+ If the user is on a `dry-run/*/*` branch, they must finish
37
+ that dry-run first (`foundry_git_finish({ message, confirm: true })`)
38
+ before re-running this skill on the parent `config/*`.
39
+
40
+ 4. `foundry/memory/config.md` exists and has `enabled: true` (run
41
+ `init-memory` first if not). Every entity type the extractor will
42
+ populate must already be declared in `foundry/memory/entities/`
43
+ (use `add-memory-entity-type` to create any that are missing).
44
+
45
+ ## Steps
46
+
47
+ ### 1. Gather inputs
48
+
49
+ Ask the user for, in this order (one question at a time):
50
+
51
+ 1. **Extractor name.** Lowercase kebab-case (`java-symbols`, `python-classes`, `tree-sitter-rust`). This becomes the filename under `foundry/memory/extractors/<name>.md` and the identifier referenced from cycle frontmatter.
52
+ 2. **Command.** The path to the executable (relative to the repo root, e.g. `scripts/extract-java-symbols.sh`) or a short shell command. This is passed to `/bin/sh -c` at runtime.
53
+ 3. **Entity types to populate (`memoryWrite`).** A list of entity type names already declared in this project's memory vocabulary. Validate against what exists; if the user names a type that doesn't exist, either offer to create it via `add-memory-entity-type` first or ask them to adjust.
54
+ 4. **Timeout** (optional). Duration string like `30s`, `2m`, or a number of milliseconds. Defaults to 60 seconds if omitted.
55
+ 5. **Brief description.** 1–3 paragraphs of prose describing what this extractor extracts, what it requires on `PATH`, and any re-run triggers. This body is injected into the forge prompt of every cycle that uses this extractor, so clarity here translates to better downstream generation.
56
+
57
+ **Security note:** Remind the user that extractors inherit the agent's full environment, including any API tokens or credentials. Extractors should keep environment variable handling internal to extraction logic.
58
+
59
+ ### 2. Propose and confirm
60
+
61
+ Summarise the proposed extractor back to the user and ask for confirmation before writing. Example:
62
+
63
+ > I'll create `foundry/memory/extractors/java-symbols.md` with:
64
+ > - command: `scripts/extract-java-symbols.sh`
65
+ > - memoryWrite: [class, method]
66
+ > - timeout: 60s (default)
67
+ > - brief: "Walks the Java source tree with tree-sitter-java…"
68
+ >
69
+ > OK to proceed?
70
+
71
+ ### 3. Create the extractor file
72
+
73
+ Call `foundry_extractor_create({ name, command, memoryWrite, body, timeout? })`. On error, surface the error to the user and stop — do not attempt to recover silently.
74
+
75
+ ### 4. Offer to scaffold the command script
76
+
77
+ If the user confirms, create the script file at the `command` path with an executable permission. Provide a starter stub that documents the JSONL contract and a minimal example. For example, for `scripts/extract-java-symbols.sh`:
78
+
79
+ ```bash
80
+ #!/bin/sh
81
+ # Emits JSONL describing Java classes and methods.
82
+ #
83
+ # JSONL Contract (one JSON object per line):
84
+ # - One JSON object per line (JSONL/NDJSON format)
85
+ # - Pretty-printed multi-line JSON is NOT supported
86
+ # - Blank lines and lines starting with '#' are ignored
87
+ # - Each object discriminated by "kind":
88
+ #
89
+ # Entities: {"kind":"entity","type":"<entity-type>","name":"<id>","value":"<string ≤ 4KB>"}
90
+ # Edges: {"kind":"edge","from":{"type":..,"name":..},"edge":"<edge-type>","to":{"type":..,"name":..}}
91
+ #
92
+ # Exit 0 on success, non-zero on failure (aborts the assay stage).
93
+ #
94
+ # Environment: This script inherits the agent's full environment, including
95
+ # any API tokens. Keep environment variable handling internal.
96
+
97
+ set -euo pipefail
98
+
99
+ # TODO: replace this stub with tree-sitter/javap/etc. invocations.
100
+ echo '{"kind":"entity","type":"class","name":"example.Foo","value":"Example class, replace me."}'
101
+ ```
102
+
103
+ Make the script executable (`chmod +x <path>`). Do **not** run the script — validation is the author's responsibility.
104
+
105
+ ### 5. Commit
106
+
107
+ Commit both the definition and (if created) the stub script:
108
+
109
+ ```bash
110
+ git add foundry/memory/extractors/<name>.md scripts/<command>
111
+ git commit -m "feat(memory): add '<name>' extractor"
112
+ ```
113
+
114
+ ### 6. Guide the user on wiring it in
115
+
116
+ After creation, tell the user how to opt a cycle into this extractor:
117
+
118
+ > To use this extractor, add the following to the cycle's frontmatter:
119
+ >
120
+ > ```yaml
121
+ > memory:
122
+ > write: [<each type in memoryWrite>] # must include every type the extractor writes
123
+ > assay:
124
+ > extractors: [<this extractor's name>]
125
+ > ```
126
+ >
127
+ > Then run the `flow` or `orchestrate` skill. On the first iteration of the cycle, the assay stage will execute this extractor before forge.
128
+
129
+ ## What this skill must not do
130
+
131
+ - **Must not** run the extractor script itself to verify it works. That is the author's job.
132
+ - **Must not** modify cycle definitions. Opting a cycle into the extractor is an explicit editorial step for the user to take.
133
+ - **Must not** create entity or edge types that don't already exist. Compose into `add-memory-entity-type` / `add-memory-edge-type` for any missing vocabulary.
@@ -10,15 +10,32 @@ You help the user create a new foundry flow. A foundry flow is a set of foundry
10
10
 
11
11
  ## Prerequisites
12
12
 
13
- Before running this skill, verify both of the following:
13
+ Before running this skill, verify all three of the following:
14
14
 
15
- 1. The `foundry/` directory exists in the project root. If it does not exist, stop and tell the user:
15
+ 1. The `foundry/` directory exists in the project root. If it does not
16
+ exist, stop and tell the user:
16
17
 
17
- > Foundry is not initialized in this project. Run the `init-foundry` skill first to create the foundry/ directory structure.
18
+ > Foundry is not initialized in this project. Run the
19
+ > `init-foundry` skill first to create the foundry/ directory
20
+ > structure.
18
21
 
19
- 2. The current git branch is not a work branch. Run `git rev-parse --abbrev-ref HEAD` — if it starts with `work/`, stop and tell the user:
22
+ 2. The current git branch is a `config/*` branch. Run
23
+ `git rev-parse --abbrev-ref HEAD` and confirm it matches
24
+ `config/<description>`.
20
25
 
21
- > You're on a work branch (`<branch>`). Foundry configuration changes must be made on the base branch (usually `main`). Complete or discard the in-flight flow (`foundry_git_finish`, or switch branches and delete it), then re-run this skill from the base branch.
26
+ 3. If the branch does not start with `config/`, instruct the user to
27
+ create one before continuing:
28
+
29
+ > Foundry configuration changes must be made on a config/* branch.
30
+ > From a clean main branch, call:
31
+ >
32
+ > `foundry_git_branch({ kind: "config", description: "<short-name>" })`
33
+ >
34
+ > Then re-run this skill.
35
+
36
+ If the user is on a `dry-run/*/*` branch, they must finish
37
+ that dry-run first (`foundry_git_finish({ message, confirm: true })`)
38
+ before re-running this skill on the parent `config/*`.
22
39
 
23
40
  ## Protocol
24
41
 
@@ -83,16 +100,25 @@ The `starting-cycles` field lists entry points. `## Cycles` lists all cycles in
83
100
 
84
101
  Ask: does this capture the flow correctly?
85
102
 
86
- ### 6. Write the file
103
+ ### 6. Validate the draft
104
+
105
+ Call `foundry_config_validate_flow({ name: "<id>", body: "<full markdown>" })`.
106
+
107
+ If the result is `{ ok: false, errors: [...] }`, address each error (adjust the body) and re-run until you get `{ ok: true }`. Common issues: missing required frontmatter keys, references to artefact types or flows that don't exist yet.
108
+
109
+ ### 7. Create the file
110
+
111
+ Call `foundry_config_create_flow({ name: "<id>", body: "<full markdown>" })`. The tool:
87
112
 
88
- Create `foundry/flows/<id>.md` with the agreed definition.
113
+ - re-validates the body (TOCTOU);
114
+ - writes `foundry/flows/<id>.md`;
115
+ - produces one git commit on the current `config/*` branch.
89
116
 
90
- ### 7. Confirm
117
+ If the tool returns `{ ok: false, errors }` because the target file already exists, the user should edit the file by hand on this `config/*` branch — `foundry_config_create_flow` does not support updates.
91
118
 
92
- Show the user the created file and its contents.
119
+ Show the user the resulting commit hash from the response.
93
120
 
94
121
  ## What you do NOT do
95
122
 
96
123
  - You do not create foundry cycles — that is a separate skill
97
- - You do not write files without showing the user first
98
124
  - You do not skip dependency validation
@@ -0,0 +1,191 @@
1
+ ---
2
+ name: add-law
3
+ type: atomic
4
+ description: Creates a new law, checking for conflicts with existing laws.
5
+ ---
6
+
7
+ # Add Law
8
+
9
+ You help the user create a new law. You ensure it's well-scoped, doesn't conflict with existing laws, and ends up in the right file.
10
+
11
+ ## Prerequisites
12
+
13
+ Before running this skill, verify all three of the following:
14
+
15
+ 1. The `foundry/` directory exists in the project root. If it does not
16
+ exist, stop and tell the user:
17
+
18
+ > Foundry is not initialized in this project. Run the
19
+ > `init-foundry` skill first to create the foundry/ directory
20
+ > structure.
21
+
22
+ 2. The current git branch is a `config/*` branch. Run
23
+ `git rev-parse --abbrev-ref HEAD` and confirm it matches
24
+ `config/<description>`.
25
+
26
+ 3. If the branch does not start with `config/`, instruct the user to
27
+ create one before continuing:
28
+
29
+ > Foundry configuration changes must be made on a config/* branch.
30
+ > From a clean main branch, call:
31
+ >
32
+ > `foundry_git_branch({ kind: "config", description: "<short-name>" })`
33
+ >
34
+ > Then re-run this skill.
35
+
36
+ If the user is on a `dry-run/*/*` branch, they must finish
37
+ that dry-run first (`foundry_git_finish({ message, confirm: true })`)
38
+ before re-running this skill on the parent `config/*`.
39
+
40
+ ## Protocol
41
+
42
+ ### 1. Determine scope
43
+
44
+ If the user specifies where the law applies:
45
+ - "global law" → goes in `foundry/laws/` (ask which file, or create a new one)
46
+ - "law for X artefacts" → goes in `foundry/artefacts/<type>/laws.md`
47
+
48
+ If the user doesn't specify, ask:
49
+
50
+ > Should this law apply globally to all artefact types, or to a specific type?
51
+
52
+ If they name a type, verify it exists in `foundry/artefacts/`. If it doesn't, tell them and ask if they want to create the artefact type first.
53
+
54
+ ### 2. Draft the law
55
+
56
+ Write the law following the standard format:
57
+
58
+ ```markdown
59
+ ## <law-id>
60
+
61
+ <What this law checks — one or two sentences.>
62
+
63
+ validators:
64
+ - id: validator-id
65
+ command: ./script.sh
66
+ failure-means: (optional description)
67
+ ```
68
+
69
+ The `law-id` (heading) should be:
70
+ - Lowercase, hyphenated
71
+ - Short but descriptive
72
+ - Unique across all laws (global and type-specific)
73
+
74
+ The `validators:` block is optional. Include it only if you want to add validation commands for this law.
75
+
76
+ ### 3. Check for conflicts
77
+
78
+ Read all existing laws that would apply to the same artefact types:
79
+ - All files in `foundry/laws/` (global)
80
+ - `foundry/artefacts/<type>/laws.md` if the law is type-specific
81
+ - If the law is global, also read all `foundry/artefacts/*/laws.md` since a global law applies everywhere
82
+
83
+ For each existing law, check:
84
+ - Does the new law contradict an existing law? (e.g., "must be formal" vs "must be conversational")
85
+ - Does the new law duplicate an existing law? (same criterion, different wording)
86
+ - Does the new law overlap with an existing law? (partially covers the same ground)
87
+
88
+ If any conflict is found, present it to the user:
89
+
90
+ > The new law `<new-id>` may conflict with existing law `<existing-id>`:
91
+ > - New: <summary of new law>
92
+ > - Existing: <summary of existing law>
93
+ > - Conflict: <what the conflict is>
94
+ >
95
+ > Options:
96
+ > 1. Proceed anyway (both laws will apply)
97
+ > 2. Replace the existing law with the new one
98
+ > 3. Rephrase the new law to avoid the conflict
99
+ > 4. Cancel
100
+
101
+ ### 4. Refine with the user
102
+
103
+ Present the drafted law to the user before writing it. Ask:
104
+
105
+ > Here's the draft law:
106
+ >
107
+ > ## <law-id>
108
+ >
109
+ > <law content>
110
+ >
111
+ > Does this capture what you want, or should we adjust the wording?
112
+
113
+ Iterate until the user is happy.
114
+
115
+ ### 5. Validate the draft
116
+
117
+ Call `foundry_config_validate_law({ name: "<file-name-without-extension>", body: "<full markdown>" })`.
118
+
119
+ If the result is `{ ok: false, errors: [...] }`, address each error (adjust the body) and re-run until you get `{ ok: true }`. Common issues: missing required frontmatter keys, references to artefact types that don't exist yet.
120
+
121
+ ### 6. Create the file
122
+
123
+ Pick the target. The user has already chosen scope in step 1 — translate that into the `target` argument:
124
+
125
+ - Global → `target: { kind: "global", file: "<file-name>.md" }` (lives at `foundry/laws/<file-name>.md`).
126
+ - Type-specific → `target: { kind: "type-specific", typeId: "<artefact-type>" }` (lives at `foundry/artefacts/<typeId>/laws.md`).
127
+
128
+ Then call:
129
+
130
+ ```
131
+ foundry_config_add_law({
132
+ name: "<file-name-without-extension>",
133
+ body: "<full markdown>",
134
+ target: { kind: "global", file: "<file-name>.md" } // OR
135
+ { kind: "type-specific", typeId: "<artefact-type>" }
136
+ })
137
+ ```
138
+
139
+ The tool:
140
+
141
+ - re-validates the body (TOCTOU);
142
+ - writes the law file at the path determined by `target`;
143
+ - produces one git commit on the current `config/*` branch.
144
+
145
+ If the tool returns `{ ok: false, errors }` because the target file already exists, use `foundry_config_edit_law({ id: "<law-id>", body: "<updated-body>" })` to modify the law.
146
+
147
+ Show the user the resulting commit hash from the response.
148
+
149
+ ### 7. Verify uniqueness
150
+
151
+ After the file is created, confirm the law id is unique across all law files. If a collision exists, ask the user to rename and edit by hand on this branch.
152
+
153
+ ### 8. Editing existing laws (prose or validators)
154
+
155
+ When the user wants to modify an existing law — whether updating the prose description or adding/changing validators — use this flow:
156
+
157
+ #### 8a. Read the existing law
158
+
159
+ Call `foundry_config_read_law({ id: "<law-id>" })` to fetch the full markdown content.
160
+
161
+ #### 8b. Refine with the user
162
+
163
+ Show the current content and ask what should change. Iterate on the updated markdown until the user is satisfied.
164
+
165
+ #### 8c. Drift mitigation: Prose changes
166
+
167
+ **If the user is modifying the law's prose description**, insert this prompt before updating:
168
+
169
+ > 🔍 **Drift check:** Verify that all existing validators on this law still accurately enforce the updated intent. Open each validator's command and confirm it catches the same class of failure the prose now describes.
170
+
171
+ Then proceed with the update.
172
+
173
+ #### 8d. Drift mitigation: Validator changes
174
+
175
+ **If the user is adding or modifying a validator**, insert this prompt before updating:
176
+
177
+ > 🔍 **Drift check:** Verify that the changed validator still aligns with the law's prose. If the validator has narrowed or broadened, the prose may need a corresponding update.
178
+
179
+ Then proceed with the update.
180
+
181
+ #### 8e. Apply the update
182
+
183
+ Call `foundry_config_edit_law({ id: "<law-id>", body: "<updated-markdown>" })` with the full updated body (prose and validators combined).
184
+
185
+ Validate the result. If the tool returns `{ ok: true }`, show the user the commit hash. If it returns `{ ok: false, errors }`, address each error and retry.
186
+
187
+ ## What you do NOT do
188
+
189
+ - You do not skip the conflict check
190
+ - You do not silently overwrite existing laws
191
+ - You do not create artefact types — that is a separate skill
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: add-memory-edge-type
3
+ type: atomic
4
+ description: Create a new edge type between entity types in flow memory
5
+ ---
6
+
7
+ # Add 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 (`foundry/memory/` exists; run `init-memory`
39
+ if not). Entity types referenced in `sources` and `targets` must
40
+ already exist (or be added first).
41
+
42
+ ## Steps
43
+
44
+ 1. **Ask the user for**: edge name (snake_case), `sources` (list of entity types or `any`), `targets` (list of entity types or `any`), and a prose body describing what the edge represents.
45
+ 2. **Push back on narrow wording**. A good edge description describes WHEN the edge holds and what it does NOT cover (boundary with related edges).
46
+ 3. **Invoke `foundry_memory_create_edge_type`** with `{ name, sources, targets, body }`.
47
+ 4. **Commit**:
48
+
49
+ ```bash
50
+ git add foundry/memory/edges/<name>.md foundry/memory/schema.json
51
+ git commit -m "feat(memory): add edge type <name>"
52
+ ```
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: add-memory-entity-type
3
+ type: atomic
4
+ description: Create a new entity type in flow memory, with a prose brief for the LLM
5
+ ---
6
+
7
+ # Add Memory Entity Type
8
+
9
+ Declare a new entity type. The prose body becomes part of every cycle's prompt and
10
+ decides what the LLM writes into memory.
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. **Ask the user for the type name** (lowercase snake_case, e.g. `class`, `stored_proc`).
47
+ 2. **Propose a prose body template** for the user to edit. Sections required: Name (naming convention for this type), Value (what goes in the value field, must state that relationships belong in edges), Relationships (informational list of likely edges). Example:
48
+
49
+ ```markdown
50
+ # <type>
51
+
52
+ Short description of what this entity represents in the subject system.
53
+
54
+ ## Name
55
+ Convention for how `name` is formed. Be specific enough to guarantee uniqueness.
56
+
57
+ ## Value
58
+ Describe what the `value` string should contain: intrinsic characteristics of
59
+ the entity only. Relationships to other entities belong in edges, not here.
60
+
61
+ ## Relationships
62
+ - `<edge>` to `<type>`: brief semantic note
63
+ ```
64
+
65
+ 3. **Confirm the body with the user.** Short bodies (≤100 chars) are a red flag; push back.
66
+ 4. **Create the type** by invoking `foundry_memory_create_entity_type` with `{ name, body }`. The tool rejects duplicate names (entity or edge) — surface the error to the user if it fires and stop.
67
+ 5. **Commit**:
68
+
69
+ ```bash
70
+ git add foundry/memory/entities/<name>.md foundry/memory/schema.json
71
+ git commit -m "feat(memory): add entity type <name>"
72
+ ```
73
+
74
+ 6. **Guidance to the user**: suggest they also add relevant edge types using `add-memory-edge-type`.
@@ -21,13 +21,25 @@ Appraise runs inside an enforced stage. Your **first** and **last** tool calls a
21
21
  1. **First:** `foundry_stage_begin({stage, cycle, token})` — copy the token verbatim from the dispatch prompt.
22
22
  2. **Last:** `foundry_stage_end({summary})`.
23
23
 
24
- Appraise makes **no disk writes**. All output flows through `foundry_feedback_add`. `foundry_stage_finalize` flags any unexpected writes as a violation.
24
+ Appraise makes **no disk writes**. Feedback output flows through `foundry_feedback_add` and `foundry_feedback_resolve`. The orchestrator's internal finalize step flags any unexpected writes as a violation.
25
25
 
26
26
  ## Protocol
27
27
 
28
28
  1. `foundry_stage_begin(...)`.
29
29
  2. Gather context:
30
30
  - `foundry_workfile_get` — read the `cycle` from frontmatter
31
+
32
+ **Check for failed flow state.** If `foundry_workfile_get` returns `{status: "failed", reason: ...}`, STOP. Do not call any other tool. Tell the user:
33
+
34
+ > The flow is in a failed state. Reason: `<reason>`.
35
+ >
36
+ > No further work is permitted. To recover:
37
+ >
38
+ > 1. `foundry_workfile_delete({confirm: true})` to abandon the cycle.
39
+ > 2. Back out to main (`git checkout main`) and delete the work branch.
40
+ > 3. Investigate and fix the root cause of the failure before restarting.
41
+
42
+ Then return control to the user and stop.
31
43
  - `foundry_artefacts_list({cycle: <current-cycle>})` — enumerate this cycle's artefacts. Always pass the `cycle` filter; omitting it returns stale rows from prior sessions. Skip rows whose status is `done` or `blocked`.
32
44
  - For each remaining row, gather its type-specific context:
33
45
  - `foundry_config_laws` with the row's type — applicable laws (global + type-specific)
@@ -43,19 +55,52 @@ Appraise makes **no disk writes**. All output flows through `foundry_feedback_ad
43
55
  - De-duplicate: merge overlapping observations into a single feedback item
44
56
  - Preserve which appraiser(s) raised each issue (for traceability)
45
57
 
46
- 6. For each consolidated issue: `foundry_feedback_add(file, text, tag: 'law:<law-id>')`. Tag MUST start with `law:` the tool rejects other tags during appraise. The tool also de-duplicates by text-hash.
58
+ 6. For each consolidated issue: `foundry_feedback_add` with `{ file, text, tag: 'law:<slug>' }`. Tags must match `law:<slug>`, and dedup uses the non-resolved `(file, tag, hash(text))` semantics described in Feedback handling.
47
59
 
48
60
  7. If no appraiser found any issues, the artefact clears appraisal.
49
61
 
50
62
  8. `foundry_stage_end({summary})`.
51
63
 
52
- ## Reviewing actioned and wont-fix feedback
53
-
54
- On subsequent passes, review previously actioned and wont-fix items:
55
-
56
- 1. `foundry_feedback_list` find `actioned` and `wont-fix` items for this artefact.
57
- 2. Appraiser sub-agents evaluate whether the change addresses the issue (`actioned`) or the justification is sound (`wont-fix`).
58
- 3. `foundry_feedback_resolve(file, index, resolution: 'approved'|'rejected', reason?)`. Appraise is the only stage (other than human-appraise) allowed to resolve `wont-fix` items.
64
+ ## Feedback handling
65
+
66
+ As an appraise stage, you have two feedback responsibilities:
67
+
68
+ 1. **Adding new law-violation feedback.** For each unmet law, call
69
+ `foundry_feedback_add` with `{ file, text, tag: 'law:<slug>' }`.
70
+ The `source` is automatically your stage id (e.g. `appraise:write-check`).
71
+ The tool rejects any tag not matching `law:<slug>` during an appraise
72
+ stage; do not attempt bare `'appraise'` or `'review'` tags.
73
+
74
+ The tool returns `{ ok: true, id, deduped }` on success. `deduped: true`
75
+ means an existing non-resolved item with the same `(file, tag,
76
+ hash(text))` was found (no new snapshot written); `deduped: false`
77
+ means a new item was created. Resolved items are NOT considered for
78
+ dedup — a re-added item after a resolution is a legitimate new item
79
+ (regression feedback).
80
+
81
+ 2. **Resolving items you sourced.** Call `foundry_feedback_list` and look
82
+ at items whose `source` exactly matches your stage id. For items whose
83
+ current state is `actioned` or `wont-fix`:
84
+ - Approve: `foundry_feedback_resolve` with `{ id, resolution: 'approved' }`.
85
+ `reason` is optional.
86
+ - Reject: `foundry_feedback_resolve` with `{ id, resolution: 'rejected', reason: '...' }`.
87
+ `reason` is required. A rejection sends the item back to forge for
88
+ another attempt (the `rejected` state is a legal forge input per
89
+ §5.1 rule 2).
90
+
91
+ **Reason rules.** `reason` is required on `resolution: 'rejected'` and on
92
+ any deadlock-override transition. On `resolution: 'approved'` for a
93
+ non-deadlocked item, `reason` is optional.
94
+
95
+ **Source-authorship rule.** You can only resolve/reject items whose `source`
96
+ matches your own stage id — not every appraise stage in the cycle, just yours.
97
+ This prevents a second appraise stage from rubber-stamping work it didn't
98
+ request. For deadlocked items, only human-appraise has the override authority.
99
+
100
+ **Future work.** Spec §17 notes a planned cycle-level mode that would let
101
+ human-appraise see non-deadlocked unresolved feedback before the orchestrator routes.
102
+ Not available in v2.6.0; appraise stages today are the sole resolver of
103
+ their own non-deadlocked items.
59
104
 
60
105
  ## Dispatch
61
106
 
@@ -67,11 +112,15 @@ Each appraiser is dispatched as an independent sub-agent. The sub-agent receives
67
112
 
68
113
  ### Model resolution
69
114
 
70
- `foundry_appraisers_select` returns raw model IDs for each appraiser. Convert each to an agent name: `foundry-<model.replace(/\//g, '-')>` (e.g., `openai/gpt-4o` becomes `foundry-openai-gpt-4o`).
115
+ `foundry_appraisers_select` returns raw model IDs for each appraiser. Convert each to an agent name: `foundry-<model.replace(/[/.]/g, '-')>` both `/` and `.` are replaced with `-`. Examples:
116
+ - `openai/gpt-4o` → `foundry-openai-gpt-4o`
117
+ - `github-copilot/claude-sonnet-4.6` → `foundry-github-copilot-claude-sonnet-4-6`
71
118
 
72
119
  - If a model is specified: dispatch with `subagent_type: "foundry-<converted-name>"`. If no agent with that name exists, **hard fail**.
73
120
  - If no model is specified: dispatch with `subagent_type: "general"` (inherits session model).
74
121
 
122
+ Note: per-appraiser `model` overrides are applied here at dispatch time. The cycle-level `models.appraise` value (if set) is used for routing-time agent-file validation only; this skill does not consult it when iterating appraisers.
123
+
75
124
  Dispatch all appraisers in parallel (multiple Task calls in a single response).
76
125
 
77
126
  ### Sub-agent prompt template
@@ -105,7 +154,7 @@ If there are no issues, return an empty list.
105
154
 
106
155
  ## History
107
156
 
108
- Do NOT call `foundry_history_append` or `foundry_git_commit` — the sort skill handles those. Return a summary via `foundry_stage_end` (e.g., "3 issues found across 2 appraisers" or "No issues found").
157
+ Do NOT call `foundry_history_append` or `foundry_git_commit` — `foundry_orchestrate` handles those (the tools are not registered publicly). Return a summary via `foundry_stage_end` (e.g., "3 issues found across 2 appraisers" or "No issues found").
109
158
 
110
159
  ### Human override awareness
111
160
 
@@ -113,8 +162,8 @@ When reviewing an artefact, check the feedback history for `#human` tagged items
113
162
 
114
163
  ## What you do NOT do
115
164
 
116
- - You do not write files — all output goes through `foundry_feedback_add`.
165
+ - You do not write files — feedback output goes through `foundry_feedback_add` and `foundry_feedback_resolve`.
117
166
  - You do not revise the artefact.
118
167
  - You do not check deterministic rules — that is the quench skill's job.
119
168
  - You do not filter out feedback because only one appraiser raised it — one is enough.
120
- - You do not register artefacts — that happens automatically via `foundry_stage_finalize`.
169
+ - You do not register artefacts — that happens automatically via the orchestrator's internal finalize step.