@really-knows-ai/foundry 3.3.0 → 3.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,64 +8,75 @@ description: Create a new extractor definition under foundry/memory/extractors/.
8
8
 
9
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
10
 
11
- ## Prerequisites
11
+ ## Foundry Agent Preflight
12
12
 
13
- Before running this skill, verify all of the following:
13
+ If you are clearly operating as the Foundry agent, continue.
14
14
 
15
- 1. The `foundry/` directory exists in the project root. If it does not
16
- exist, stop and tell the user:
15
+ If you are not clearly operating as the Foundry agent, pause and tell the user:
17
16
 
18
- > Restart OpenCode to initialise Foundry, then retry this command.
17
+ > This work is best handled by the Foundry agent. Restart OpenCode if you have just initialised Foundry, switch to the **Foundry** agent, and continue this request there.
19
18
 
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>`.
19
+ This is an advisory guard. Continue only when the active instructions make it clear you are the Foundry agent or the user explicitly asks to proceed here.
23
20
 
24
- 3. If the branch does not start with `config/`, move to a suitable
25
- `config/*` branch internally when the current branch is safe. If
26
- the current branch is `work/*` or `dry-run/*/*`, stop and explain
27
- the active work must be finished first. When unrelated uncommitted
28
- changes could be affected by branching or writing files, ask before
29
- proceeding.
21
+ ## Config Branch Handling
30
22
 
31
- 4. `foundry/memory/config.md` exists and has `enabled: true` (initialise
32
- memory internally first if not). Missing memory entity or edge type
33
- dependencies are created or composed internally when they are part of
34
- the user's stated goal.
23
+ Before writing Foundry configuration:
35
24
 
36
- ## Steps
25
+ - Confirm `foundry/` exists. If it is missing, initialise Foundry first when that serves the user's goal.
26
+ - Check the current branch.
27
+ - On `main` or another clean non-work branch, create a `config/<short-description>` branch internally.
28
+ - On `config/*`, continue on the current branch.
29
+ - On `work/*`, stop and explain that active flow work must be finished before configuration changes.
30
+ - On `dry-run/*/*`, stop and explain that the dry run must be finished before configuration changes.
31
+ - If unrelated uncommitted changes could be affected by branching or writing files, ask before proceeding.
37
32
 
38
- ### 1. Gather inputs
33
+ Do not tell the user to call branch tools directly.
39
34
 
40
- Ask the user for, in this order (one question at a time):
35
+ `foundry/memory/config.md` must exist with `enabled: true`. Initialise memory internally first if not. Missing memory entity or edge type dependencies are composed internally when they are part of the user's stated goal.
36
+
37
+ ## Protocol
38
+
39
+ ### 1. Understand
40
+
41
+ Ask the user for each field one question at a time, in this order:
41
42
 
42
43
  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.
43
44
  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.
44
45
  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, compose or create it internally when it is part of the user's stated goal, or ask one focused question when schema design is ambiguous.
45
- 4. **Timeout** (optional). Duration string like `30s`, `2m`, or a number of milliseconds. Defaults to 60 seconds if omitted.
46
+ 4. **Timeout** (optional). Present as a choice:
47
+
48
+ > Set a timeout for this extractor?
49
+ > 1. 60 seconds (Recommended)
50
+ > 2. Custom duration (specify as `30s`, `2m`, or milliseconds)
46
51
  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.
47
52
 
48
53
  **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.
49
54
 
50
- ### 2. Propose and confirm
55
+ ### 2. Plan
51
56
 
52
- Summarise the proposed extractor back to the user and ask for confirmation before writing. Example:
57
+ Summarise the proposed extractor back to the user and invite refinement. Include the extractor name, command, memory write path, description, and timeout. Ask: "Does this capture the extractor correctly?" Example:
53
58
 
54
59
  > I'll create `foundry/memory/extractors/java-symbols.md` with:
55
60
  > - command: `scripts/extract-java-symbols.sh`
56
61
  > - memoryWrite: [class, method]
57
- > - timeout: 60s (default)
62
+ > - timeout: 60s
58
63
  > - brief: "Walks the Java source tree with tree-sitter-java…"
59
64
  >
60
- > OK to proceed?
65
+ > Does this capture the extractor correctly?
61
66
 
62
- ### 3. Create the extractor file
67
+ ### 3. Confirm
63
68
 
64
- 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.
69
+ Ask: "Proceed with this plan?" wait for the user to answer. Do not proceed to Build unless the user says yes. If the user rejects the plan, return to the Understand phase and adjust.
65
70
 
66
- ### 4. Offer to scaffold the command script
71
+ ### 4. Build
67
72
 
68
- 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`:
73
+ 1. **Create**: Call `foundry_extractor_create({ name: "<name>", command: "<command>", memoryWrite: ["<type>", ...], body: "<description>", timeout: "<optional>" })`. On error, surface the error to the user and stop do not attempt to recover silently.
74
+
75
+ 2. **Commit**: Run `git add foundry/memory/extractors/<name>.md` plus the command script path if one was created. Run `git commit -m "feat(memory): add '<name>' extractor"`. Report the commit hash.
76
+
77
+ #### Post-Build — scaffold the command script
78
+
79
+ When the user has confirmed, create the script file at the `command` path with executable permission. Provide a starter stub that documents the JSONL contract and a minimal example:
69
80
 
70
81
  ```bash
71
82
  #!/bin/sh
@@ -93,27 +104,12 @@ echo '{"kind":"entity","type":"class","name":"example.Foo","value":"Example clas
93
104
 
94
105
  Make the script executable (`chmod +x <path>`). Do **not** run the script — validation is the author's responsibility.
95
106
 
96
- ### 5. Commit
107
+ #### Post-Build — compose into a cycle
97
108
 
98
- Commit both the definition and (if created) the stub script:
109
+ When the user's stated goal is to add memory extraction to a flow or cycle, compose this extractor into the relevant cycle definition. Update the cycle definition internally to add the `extractors` and `memoryWrite` fields. Ask for confirmation or one focused question when cycle selection or wiring is ambiguous.
99
110
 
100
- ```bash
101
- git add foundry/memory/extractors/<name>.md scripts/<command>
102
- git commit -m "feat(memory): add '<name>' extractor"
103
- ```
104
-
105
- ### 6. Compose into a cycle when the user's goal requires it
106
-
107
- When the user's stated goal is to add memory extraction to a flow or cycle, compose this extractor into the relevant cycle definition. See **Composing cycle definitions** below.
108
-
109
- ## Dependency composition
110
-
111
- Missing memory entity or edge type dependencies are **composed internally** when they are part of the user's stated goal. Compose into the appropriate memory vocabulary when schema design is ambiguous — ask one focused question rather than stalling.
111
+ Compose into the appropriate memory vocabulary when schema design is ambiguous — ask one focused question rather than stalling.
112
112
 
113
113
  ## What this skill must not do
114
114
 
115
115
  - **Must not** run the extractor script itself to verify it works. That is the author's job.
116
-
117
- ## Composing cycle definitions
118
-
119
- When the user's stated goal includes opting an existing cycle into this extractor, update the cycle definition internally to add the `extractors` and `memoryWrite` fields. Ask for confirmation or one focused question when cycle selection or wiring is ambiguous.
@@ -38,47 +38,114 @@ Do not tell the user to call branch tools directly.
38
38
 
39
39
  Extract or ask for the flow purpose, expected final artefact, output location, and any quality constraints. Prefer practical defaults for common requests.
40
40
 
41
- ### 2. Inventory existing configuration
41
+ **Flow basics**: Gather the flow's own required fields:
42
+ - `id` — lowercase, hyphenated identifier. Reject duplicate IDs — if a flow with the same ID already exists, choose a different ID. Warn about semantic duplicates (different ID but near-identical purpose) and ask whether the new flow is genuinely distinct.
43
+ - `name` — human-readable name
44
+ - `description` — prose description of the flow purpose
42
45
 
43
- Read existing flows in `foundry/flows/*.md`, cycles in `foundry/cycles/*.md`, artefact types in `foundry/artefacts/*/definition.md`, laws in `foundry/laws/*.md`, and appraisers in `foundry/appraisers/*.md`. Identify reusable pieces and conflicts.
46
+ **What the flow produces**: Ask about the artefact type the flow should produce. Determine whether it needs a new artefact type or whether an existing one fits.
44
47
 
45
- Reject duplicate flow IDs if a flow with the same ID already exists, choose a different ID. Warn about semantic duplicates (different ID but near-identical purpose) and ask whether the new flow is genuinely distinct.
48
+ **Quality constraints**: Ask about the laws that govern quality. For each law: what it checks, whether it applies globally or to a specific artefact type, and the deterministic-vs-subjective split.
46
49
 
47
- ### 3. Design the dependency set
50
+ **Appraisers**: Ask about the appraisers that evaluate quality. Determine how many are needed and whether existing appraisers fit or new ones are needed.
51
+
52
+ **Cycles**: Ask about the cycles that process the artefact. Determine how many cycles there are and what each produces.
53
+
54
+ **Starting cycles**: Identify which cycle IDs begin the flow.
55
+
56
+ **Cycle graph validation**: After designing the cycles, validate the cycle graph: verify each non-starting cycle is reachable from a starting cycle through the `targets` graph, and verify each cycle's input contracts can be satisfied by other cycles in the flow. Warn about unreachable cycles or unsatisfiable contracts before proceeding.
57
+
58
+ **Inventory**: Read existing flows in `foundry/flows/*.md`, cycles in `foundry/cycles/*.md`, artefact types in `foundry/artefacts/*/definition.md`, laws in `foundry/laws/*.md`, and appraisers in `foundry/appraisers/*.md`. Identify reusable pieces and conflicts.
59
+
60
+ ### 2. Gather requirements for each dependency
61
+
62
+ For each dependency type in dependency order, ask questions to build a context object. This is the Understand phase for each sub-skill — the answers are captured and passed along when building.
48
63
 
49
64
  Create missing dependencies in validation order:
50
65
 
51
- 1. Artefact type and file patterns.
52
- 2. Type-specific laws.
53
- 3. Deterministic validators attached to laws.
54
- 4. Appraisers or appraiser selection.
55
- 5. Cycles that produce the artefact types.
56
- 6. Flow tying starting cycles and cycle list together.
66
+ 1. **Artefact types** (no sub-dependencies): For each new artefact type, gather `id`, `name`, `filePatterns`, `description`, and whether it needs type-specific laws or appraiser configuration. Context object: `{id, name, filePatterns, description, appraisers?}`.
67
+
68
+ 2. **Laws** (may reference artefact types): For each new law, gather `id`, `name`, `description`, `passing`, `failing`, the target (global file or type-specific with `typeId`), and the deterministic-vs-subjective split. Determine whether validators are needed. Context object: `{id, name, description, passing, failing, target: {kind, file|typeId}, validators?}`.
69
+
70
+ 3. **Appraisers** (may reference models): For each new appraiser, gather `id`, `name`, `description`, and optional `model` preference. Context object: `{id, name, description, model?}`.
71
+
72
+ 4. **Cycles** (reference artefact types, laws, appraisers): For each new cycle, gather `id`, `name`, `outputType`, `description`, and any optional settings (inputs, targets, appraise, assay, memory, models). Context object: `{id, name, outputType, description, inputs?, targets?, humanAppraise?, deadlockAppraise?, deadlockIterations?, maxIterations?, assay?, memory?, models?}`.
57
73
 
58
74
  For the haiku example, default to a `haiku` artefact type, `haikus/*.md` file pattern, laws for form, imagery, and mood, a deterministic syllable validator where project dependencies allow it, two or three distinct appraisers, one cycle, and one flow.
59
75
 
60
- After designing cycles, validate the cycle graph: verify each non-starting cycle is reachable from a starting cycle through the `targets` graph, and verify each cycle's input contracts can be satisfied by other cycles in the flow. Warn about unreachable cycles or unsatisfiable contracts before proceeding.
76
+ For each dependency, determine whether it already exists (user says "use the existing haiku artefact type") or needs to be created. If it already exists, capture its id for reference. If it needs creating, capture the context object fields.
77
+
78
+ ### 3. Present the combined plan
79
+
80
+ Show the full dependency tree as a structured summary:
81
+
82
+ ```text
83
+ Flow: <id> — <name>
84
+ Starting cycles: <cycle-id>, ...
85
+ Description: <description>
86
+ Artefact Types:
87
+ · <id> (<name>) — <filePatterns>
88
+ Laws:
89
+ · <id> — <description> [deterministic|subjective]
90
+ validators: <validator-id> (if deterministic)
91
+ Appraisers:
92
+ · <id> — <description>
93
+ Cycles:
94
+ · <id> → <outputType> — <description>
95
+ ```
96
+
97
+ Ask "Proceed with this plan?" — do not build anything until the user confirms.
98
+
99
+ If the user rejects the plan, return to the Understand phase and adjust.
100
+
101
+ ### 4. Build dependencies in order
102
+
103
+ For each dependency, invoke the sub-skill's protocol with the captured context object. The context object for each sub-skill matches the args of the corresponding `foundry_config_create_*` tool, with fields populated from the Understand and Gather phases.
104
+
105
+ Build order (dependency order):
106
+
107
+ 1. **Artefact types**: For each new artefact type, invoke the `add-artefact-type` protocol with the captured context. Example:
108
+
109
+ > Invoke the add-artefact-type protocol with context: `{id: "haiku", name: "Haiku", filePatterns: ["haikus/*.md"], description: "A traditional Japanese poem"}`.
110
+ > The add-artefact-type skill checks its Context object section. If all required fields are present, it proceeds directly to Build, skipping Understand, Plan, and Confirm. If only some fields are present, it asks only for the missing ones and proceeds to Build — it skips Plan and Confirm since the parent's combined plan already handled confirmation.
111
+
112
+ 2. **Laws**: For each new law, invoke the `add-law` protocol with the captured context. Example:
113
+
114
+ > Invoke the add-law protocol with context: `{id: "three-lines", name: "Three Lines", description: "must have exactly three lines", passing: "...", failing: "...", target: {kind: "type-specific", typeId: "haiku"}}`.
115
+ > If all required fields are present, the sub-skill proceeds directly to Build. Otherwise it asks only for the missing required fields, then proceeds to Build.
116
+
117
+ 3. **Appraisers**: For each new appraiser, invoke the `add-appraiser` protocol with the captured context.
118
+
119
+ > Invoke the add-appraiser protocol with context: `{id: "haiku-critic", name: "Haiku Critic", description: "Evaluates haiku structure and imagery"}`.
120
+ > If all required fields are present, proceed directly to Build. Otherwise ask for missing required fields only.
121
+
122
+ 4. **Cycles**: For each new cycle, invoke the `add-cycle` protocol with the captured context.
123
+
124
+ > Invoke the add-cycle protocol with context: `{id: "haiku-cycle", name: "Haiku Cycle", outputType: "haiku", description: "Generates haiku poems"}`.
125
+ > If all required fields are present, proceed directly to Build. Otherwise ask for missing required fields only.
126
+
127
+ **Build-only mode**: When all required fields for a sub-skill are present in the context, the sub-skill skips Understand, Plan, and Confirm — proceeding directly to validate → create → commit. When only some required fields are present, the sub-skill enters its Understand phase to ask only for those missing required fields, then proceeds to Build (still skipping Plan and Confirm since the parent's combined plan already handled confirmation). Optional fields that are missing are silently skipped.
61
128
 
62
- ### 4. Confirm ambiguous choices
129
+ **Error handling during build**: If a sub-skill's Build phase fails (validation error or tool error), surface the error to the user:
63
130
 
64
- Ask only for choices that affect the user's goal or safety. Reuse compatible existing configuration when it clearly fits.
131
+ > Build of `<piece>` failed: `<error>`. Retry, skip this piece, or abort?
65
132
 
66
- ### 5. Validate and create each piece
133
+ Do not silently skip or auto-resolve.
67
134
 
68
- For each definition, use the `foundry_config_validate_*` tool family to validate it first. Resolve any validation errors, then use the corresponding `foundry_config_create_*` tool to create it. Summarise each created file and commit hash in Foundry terms.
135
+ ### 5. Build the flow
69
136
 
70
- For the flow definition itself, use these structured fields:
137
+ After all dependencies are built, create the flow itself:
71
138
 
72
- - `id` (string) lowercase, hyphenated identifier
73
- - `name` (string) — human-readable name
74
- - `description` (string) — prose description of the flow purpose
75
- - `startingCycles` (string[]) — cycle IDs that begin the flow
139
+ 1. **Validate**: Call `foundry_config_validate_flow({ name: "<id>", body: "<assembled markdown>" })`. Assemble the body from the fields using the frontmatter format the tool produces internally. If the result is `{ ok: false, errors: [...] }`, address each error and re-run until `{ ok: true }`. Common issues: missing required frontmatter keys, references to artefact types or cycles that do not exist yet.
76
140
 
77
- Call `foundry_config_create_flow({ id: "<id>", name: "<name>", startingCycles: ["<id>"], description: "<description>" })` to create the flow file.
141
+ 2. **Create**: Call `foundry_config_create_flow({ id: "<id>", name: "<name>", startingCycles: ["<cycle-id>", ...], description: "<description>" })`. The tool:
142
+ - re-validates the body (TOCTOU);
143
+ - writes `foundry/flows/<id>.md`;
144
+ - produces one git commit on the current `config/*` branch.
78
145
 
79
- ### 6. Final summary
146
+ If the tool returns `{ ok: false, errors }` because the target file already exists, read the existing flow file, incorporate the user's requested changes into the current body, propose the merged result for review, then write and commit the updated file.
80
147
 
81
- Report the flow, starting cycles, artefact type, laws, validators, appraisers, and files created. Tell the user they can now ask the Foundry agent to run the flow.
148
+ 3. **Report**: Show the user the flow file and the commit hash. Also summarise each dependency that was created, with its commit hash. Tell the user they can now ask the Foundry agent to run the flow.
82
149
 
83
150
  ## Safety Rules
84
151
 
@@ -34,47 +34,43 @@ Do not tell the user to call branch tools directly.
34
34
 
35
35
  ## Protocol
36
36
 
37
- ### 1. Determine scope
37
+ ### Context object
38
38
 
39
- If the user specifies where the law applies:
40
- - "global law" → goes in `foundry/laws/` (ask which file, or create a new one)
41
- - "law for X artefacts" → goes in `foundry/artefacts/<type>/laws.md`
39
+ When invoked with pre-filled fields matching the `foundry_config_add_law` tool args, skip questions for provided fields. Missing fields trigger clarifying questions.
42
40
 
43
- If the user doesn't specify, ask:
41
+ Context fields (global): `{id, name, description, passing, failing, target: {kind: "global", file}, validators?}`
42
+ Context fields (type-specific): `{id, name, description, passing, failing, target: {kind: "type-specific", typeId}, validators?}`
44
43
 
45
- > Should this law apply globally to all artefact types, or to a specific type?
44
+ When invoked with a context:
45
+ - If all required fields are present, skip the Understand phase and proceed to Plan → Confirm → Build.
46
+ - If only some fields are present, ask only for the missing ones.
46
47
 
47
- If the user names a type-specific law for an artefact type that does not exist, create the artefact type first when that supports the user's stated goal. Use the `add-artefact-type` workflow internally, and ask for the file pattern only when it cannot be inferred safely.
48
+ ### 1. Understand
48
49
 
49
- ### 2. Draft the law
50
+ **Scope**: Ask "Should this law apply globally to all artefact types, or to a specific type?" If the user names a type-specific law for an artefact type that does not exist, create the artefact type first when that supports the user's stated goal using the `add-artefact-type` workflow internally.
50
51
 
51
- Write the law using these structured fields:
52
+ If global, ask for the `file` (the filename under `foundry/laws/`, e.g. `rules.md`). If type-specific, ask for the `typeId`.
52
53
 
53
- - `id` (string) lowercase, hyphenated law identifier, unique across all laws
54
- - `name` (string) — human-readable name
55
- - `description` (string) — one or two sentences describing what this law checks
56
- - `passing` (string) — description of what passing looks like
57
- - `failing` (string) — description of what failing looks like
58
- - `validators` (array, optional) — validator entries. Include only when a deterministic check can decide pass/fail. See **Validator contract** below for the exact shape a validator command must satisfy.
54
+ **Fields**: Ask for `id`, `name`, `description`, `passing` criteria, and `failing` criteria one at a time.
59
55
 
60
- The `id` value should be:
61
- - Lowercase, hyphenated
62
- - Short but descriptive
63
- - Unique across all laws (global and type-specific)
56
+ **Deterministic vs subjective split**: For each law, explicitly split what it checks into two categories:
64
57
 
65
- ### 3. Check for conflicts
58
+ - **Deterministic** — can be checked by a script without human or LLM judgment. Examples: line count, syllable count, word minimum, forbidden patterns, file existence, formatting rules. These become `validators:` entries in the law.
59
+ - **Subjective** — requires judgment. Examples: imagery quality, emotional resonance, persuasiveness, aesthetic appeal, clarity of argument. The appraisers evaluate these during the appraise stage. No validator entry needed; the law's prose alone guides the appraiser.
66
60
 
67
- Read all existing laws that would apply to the same artefact types:
68
- - All files in `foundry/laws/` (global)
69
- - `foundry/artefacts/<type>/laws.md` if the law is type-specific
70
- - If the law is global, also read all `foundry/artefacts/*/laws.md` since a global law applies everywhere
61
+ Walk the user through this split for each law:
71
62
 
72
- For each existing law, check:
73
- - Does the new law contradict an existing law? (e.g., "must be formal" vs "must be conversational")
74
- - Does the new law duplicate an existing law? (same criterion, different wording)
75
- - Does the new law overlap with an existing law? (partially covers the same ground)
63
+ > This law covers [summary]. Here's what's deterministic vs subjective:
64
+ > - Deterministic: [list elements that can be script-checked]
65
+ > - Subjective: [list elements requiring judgment appraisers handle these]
66
+ >
67
+ > Shall I add validators for the deterministic elements?
68
+
69
+ For each deterministic element, write a standalone `.mjs` script next to the artefacts it validates (e.g. `foundry/artefacts/<type>/check-line-count.mjs`) and reference it in the command (e.g. `node foundry/artefacts/<type>/check-line-count.mjs {files}`). Place validators alongside the artefacts so they colocate with what they validate. Prefer Node.js built-ins and libraries already in the project; hand-rolled heuristics are fragile — use available packages instead of writing custom validation logic from scratch.
76
70
 
77
- If any conflict is found, present it to the user:
71
+ **Validators**: Ask about `validators` (optional) offer to create one or skip.
72
+
73
+ **Conflict check**: Read all existing laws that would apply to the same artefact types. Check for contradiction, duplication, or overlap. If any conflict is found, present it to the user:
78
74
 
79
75
  > The new law `<new-id>` may conflict with existing law `<existing-id>`:
80
76
  > - New: <summary of new law>
@@ -87,66 +83,77 @@ If any conflict is found, present it to the user:
87
83
  > 3. Rephrase the new law to avoid the conflict
88
84
  > 4. Cancel
89
85
 
90
- ### 4. Refine with the user
86
+ ### 2. Plan
91
87
 
92
- Present the drafted law to the user before writing it. Ask:
88
+ Present a structured summary: law id, name, description, passing/failing criteria, target (global or type-specific with typeId), deterministic/subjective split, validators. Ask: "Does this capture what you want, or should we adjust the wording?" Iterate until the user is satisfied.
93
89
 
94
- > Here's the draft law:
95
- >
96
- > ## <law-id>
97
- >
98
- > <law content>
99
- >
100
- > Does this capture what you want, or should we adjust the wording?
90
+ ### 3. Confirm
91
+
92
+ Ask: "Proceed with this plan?" — wait for user answer before building. If the user rejects the plan, return to the Understand phase and adjust.
93
+
94
+ ### 4. Build
95
+
96
+ 1. **Validate**: Call `foundry_config_validate_law({ name: "<id>", body: "<assembled markdown>" })`. Assemble the body from the fields using the `## <id>` heading format the tool produces internally. If the result is `{ ok: false, errors: [...] }`, address each error and re-run until `{ ok: true }`. Common issues: missing required frontmatter keys, references to artefact types that do not exist yet.
97
+
98
+ 2. **Create**: Translate the scope into the `target` argument:
99
+ - Global → `target: { kind: "global", file: "<file-name>.md" }`
100
+ - Type-specific → `target: { kind: "type-specific", typeId: "<artefact-type>" }`
101
+
102
+ Call:
103
+
104
+ ```
105
+ foundry_config_add_law({
106
+ id: "<id>",
107
+ name: "<name>",
108
+ description: "<description>",
109
+ passing: "<passing>",
110
+ failing: "<failing>",
111
+ target: { kind: "global", file: "<file-name>.md" }
112
+ // or { kind: "type-specific", typeId: "<artefact-type>" }
113
+ })
114
+ ```
115
+
116
+ The tool re-validates the body (TOCTOU), writes the law file at the path determined by `target`, and produces one git commit on the current `config/*` branch. Show the user the resulting commit hash.
117
+
118
+ The tool appends to an existing `laws.md` automatically when the new law id is not already present. It only errors when a law with the same id is already in the file — in that case use `foundry_config_edit_law({ id: "<law-id>", description: "<updated>", passing: "<updated>", failing: "<updated>" })` to modify the existing law in place.
101
119
 
102
- Iterate until the user is happy.
120
+ 3. **Verify uniqueness**: After the file is created, confirm the law id is unique across all law files. If a collision exists, read the colliding law, present the conflict to the user, propose a rename or merge, ask one focused question about the user's preference, then write and commit the resolution.
103
121
 
104
- ### 5. Validate the draft
122
+ ### 5. Editing existing laws (prose or validators)
105
123
 
106
- Call `foundry_config_validate_law({ name: "<id>", body: "<assembled markdown>" })`. Assemble the body from the fields using the `## <id>` heading format the tool produces internally.
124
+ When the user wants to modify an existing law whether updating the prose description or adding/changing validators use this flow:
125
+
126
+ #### 5a. Read the existing law
107
127
 
108
- 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.
128
+ Call `foundry_config_read_law({ id: "<law-id>" })` to fetch the full markdown content.
109
129
 
110
- ### 6. Create the file
130
+ #### 5b. Refine with the user
111
131
 
112
- Pick the target. The user has already chosen scope in step 1 translate that into the `target` argument:
132
+ Show the current content and ask what should change. Iterate on the updated markdown until the user is satisfied.
133
+
134
+ #### 5c. Drift mitigation: Prose changes
135
+
136
+ **If the user is modifying the law's prose description**, insert this prompt before updating:
113
137
 
114
- - Global `target: { kind: "global", file: "<file-name>.md" }` (lives at `foundry/laws/<file-name>.md`).
115
- - Type-specific → `target: { kind: "type-specific", typeId: "<artefact-type>" }` (lives at `foundry/artefacts/<typeId>/laws.md`).
138
+ > 🔍 **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.
116
139
 
117
- Then call:
140
+ Then proceed with the update.
118
141
 
119
- ```
120
- foundry_config_add_law({
121
- id: "<id>",
122
- name: "<name>",
123
- description: "<description>",
124
- passing: "<passing>",
125
- failing: "<failing>",
126
- target: { kind: "global", file: "<file-name>.md" } // OR
127
- { kind: "type-specific", typeId: "<artefact-type>" }
128
- })
129
- ```
142
+ #### 5d. Drift mitigation: Validator changes
130
143
 
131
- The tool:
144
+ **If the user is adding or modifying a validator**, insert this prompt before updating:
132
145
 
133
- - re-validates the body (TOCTOU);
134
- - writes the law file at the path determined by `target`;
135
- - produces one git commit on the current `config/*` branch.
146
+ > 🔍 **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.
136
147
 
137
- The tool appends to an existing `laws.md` automatically when the
138
- new law id is not already present. It only errors when
139
- a law with the same id is already in the file — in that case use
140
- `foundry_config_edit_law({ id: "<law-id>", description: "<updated>", passing: "<updated>", failing: "<updated>" })`
141
- to modify the existing law in place.
148
+ Then proceed with the update.
142
149
 
143
- Show the user the resulting commit hash from the response.
150
+ #### 5e. Apply the update
144
151
 
145
- ### 7. Verify uniqueness
152
+ Call `foundry_config_edit_law({ id: "<law-id>", description: "<updated>", passing: "<updated>", failing: "<updated>", validators: [...] })` with the full updated fields.
146
153
 
147
- After the file is created, confirm the law id is unique across all law files. If a collision exists, read the colliding law, present the conflict to the user, propose a rename or merge, ask one focused question about the user's preference, then write and commit the resolution.
154
+ 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.
148
155
 
149
- ### 7a. Validator contract
156
+ ### 6. Validator contract
150
157
 
151
158
  A law's `validators:` entries declare CLI commands that `quench` runs
152
159
  during a cycle. The plugin parses each command's stdout as **JSONL**
@@ -251,40 +258,6 @@ validators:
251
258
  failure-means: The artefact file does not contain exactly three non-empty lines.
252
259
  ~~~
253
260
 
254
- ### 8. Editing existing laws (prose or validators)
255
-
256
- When the user wants to modify an existing law — whether updating the prose description or adding/changing validators — use this flow:
257
-
258
- #### 8a. Read the existing law
259
-
260
- Call `foundry_config_read_law({ id: "<law-id>" })` to fetch the full markdown content.
261
-
262
- #### 8b. Refine with the user
263
-
264
- Show the current content and ask what should change. Iterate on the updated markdown until the user is satisfied.
265
-
266
- #### 8c. Drift mitigation: Prose changes
267
-
268
- **If the user is modifying the law's prose description**, insert this prompt before updating:
269
-
270
- > 🔍 **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.
271
-
272
- Then proceed with the update.
273
-
274
- #### 8d. Drift mitigation: Validator changes
275
-
276
- **If the user is adding or modifying a validator**, insert this prompt before updating:
277
-
278
- > 🔍 **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.
279
-
280
- Then proceed with the update.
281
-
282
- #### 8e. Apply the update
283
-
284
- Call `foundry_config_edit_law({ id: "<law-id>", description: "<updated>", passing: "<updated>", failing: "<updated>", validators: [...] })` with the full updated fields.
285
-
286
- 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.
287
-
288
261
  ## What you do NOT do
289
262
 
290
263
  - You do not skip the conflict check
@@ -6,39 +6,68 @@ description: Create a new edge type between entity types in flow memory
6
6
 
7
7
  # Add Memory Edge Type
8
8
 
9
- ## Prerequisites
9
+ ## Foundry Agent Preflight
10
10
 
11
- Before running this skill, verify all of the following:
11
+ If you are clearly operating as the Foundry agent, continue.
12
12
 
13
- 1. The `foundry/` directory exists in the project root. If it does not
14
- exist, stop and tell the user:
13
+ If you are not clearly operating as the Foundry agent, pause and tell the user:
15
14
 
16
- > Restart OpenCode to initialise Foundry, then retry this command.
15
+ > This work is best handled by the Foundry agent. Restart OpenCode if you have just initialised Foundry, switch to the **Foundry** agent, and continue this request there.
17
16
 
18
- 2. The current git branch is a `config/*` branch. Run
19
- `git rev-parse --abbrev-ref HEAD` and confirm it matches
20
- `config/<description>`.
17
+ This is an advisory guard. Continue only when the active instructions make it clear you are the Foundry agent or the user explicitly asks to proceed here.
21
18
 
22
- 3. If the branch does not start with `config/`, move to a suitable
23
- `config/*` branch internally when the current branch is safe. If
24
- the current branch is `work/*` or `dry-run/*/*`, stop and explain
25
- the active work must be finished first. When unrelated uncommitted
26
- changes could be affected by branching or writing files, ask before
27
- proceeding.
19
+ ## Config Branch Handling
28
20
 
29
- 4. Memory is initialised (`foundry/memory/` exists; initialise memory
30
- internally first if not). Entity types referenced in `sources` and
31
- `targets` must already exist (or be created or composed internally
32
- when they are part of the user's stated goal).
21
+ Before writing Foundry configuration:
33
22
 
34
- ## Steps
23
+ - Confirm `foundry/` exists. If it is missing, initialise Foundry first when that serves the user's goal.
24
+ - Check the current branch.
25
+ - On `main` or another clean non-work branch, create a `config/<short-description>` branch internally.
26
+ - On `config/*`, continue on the current branch.
27
+ - On `work/*`, stop and explain that active flow work must be finished before configuration changes.
28
+ - On `dry-run/*/*`, stop and explain that the dry run must be finished before configuration changes.
29
+ - If unrelated uncommitted changes could be affected by branching or writing files, ask before proceeding.
35
30
 
36
- 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.
37
- 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).
38
- 3. **Invoke `foundry_memory_create_edge_type`** with `{ name, sources, targets, body }`.
39
- 4. **Commit**:
31
+ Do not tell the user to call branch tools directly.
40
32
 
41
- ```bash
42
- git add foundry/memory/edges/<name>.md foundry/memory/schema.json
43
- git commit -m "feat(memory): add edge type <name>"
44
- ```
33
+ Memory must be initialised (`foundry/memory/` must exist). Initialise memory internally first if not. Entity types referenced in `sources` and `targets` must already exist — create or compose them internally when they are part of the user's stated goal, or ask one focused question when schema design is ambiguous.
34
+
35
+ ## Protocol
36
+
37
+ ### Context object
38
+
39
+ When invoked with pre-filled fields matching the `foundry_memory_create_edge_type` tool args, skip questions for provided fields. Missing fields trigger clarifying questions.
40
+
41
+ Context fields: `{name, sources, targets, body}`
42
+
43
+ When invoked with a context:
44
+ - If all required fields are present, skip the Understand phase and proceed to Plan → Confirm → Build.
45
+ - If only some fields are present, ask only for the missing ones.
46
+
47
+ ### 1. Understand
48
+
49
+ Ask for each field one question at a time:
50
+
51
+ 1. **Edge name.** Lowercase snake_case.
52
+ 2. **Sources.** The entity types this edge originates from. List existing entity types from `foundry/memory/entities/` as multiple-choice options. Allow `any`.
53
+ 3. **Targets.** The entity types this edge points to. List existing entity types as multiple-choice options. Allow `any`.
54
+ 4. **Prose body.** A description of what this edge represents. Push back on narrow wording — a good edge description describes when the edge holds and what it does not cover (boundary with related edges). Suggest a clearer alternative when the user provides vague wording and ask before proceeding.
55
+
56
+ ### 2. Plan
57
+
58
+ Present the edge type definition: name, sources, targets, body. Ask: "Does this capture the edge type correctly?" Iterate until the user is satisfied.
59
+
60
+ ### 3. Confirm
61
+
62
+ Ask: "Proceed with this plan?" — wait for user answer before building. If the user rejects the plan, return to the Understand phase and adjust.
63
+
64
+ ### 4. Build
65
+
66
+ 1. **Validate**: Call `foundry_memory_validate`. If the result is `{ ok: false, errors: [...] }`, address each error and re-run until `{ ok: true }`.
67
+ 2. **Create**: Call `foundry_memory_create_edge_type({ name: "<name>", sources: ["<type>", ...], targets: ["<type>", ...], body: "<body>" })`.
68
+ 3. **Commit**: Run `git add foundry/memory/edges/<name>.md foundry/memory/schema.json`. Run `git commit -m "feat(memory): add edge type <name>"`. Report the commit hash.
69
+
70
+ ## What you do NOT do
71
+
72
+ - You do not delegate memory initialisation to the user — initialise internally when needed
73
+ - You do not create edge types with sources or targets that don't exist — compose them internally when they serve the user's stated goal