@really-knows-ai/foundry 3.3.1 → 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,32 +34,26 @@ 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
- #### 2a. Identify deterministic vs subjective elements
61
-
62
- For each law, explicitly split what it checks into two categories:
56
+ **Deterministic vs subjective split**: For each law, explicitly split what it checks into two categories:
63
57
 
64
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.
65
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.
@@ -74,24 +68,9 @@ Walk the user through this split for each law:
74
68
 
75
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
- The `id` value should be:
78
- - Lowercase, hyphenated
79
- - Short but descriptive
80
- - Unique across all laws (global and type-specific)
81
-
82
- ### 3. Check for conflicts
83
-
84
- Read all existing laws that would apply to the same artefact types:
85
- - All files in `foundry/laws/` (global)
86
- - `foundry/artefacts/<type>/laws.md` if the law is type-specific
87
- - If the law is global, also read all `foundry/artefacts/*/laws.md` since a global law applies everywhere
88
-
89
- For each existing law, check:
90
- - Does the new law contradict an existing law? (e.g., "must be formal" vs "must be conversational")
91
- - Does the new law duplicate an existing law? (same criterion, different wording)
92
- - Does the new law overlap with an existing law? (partially covers the same ground)
71
+ **Validators**: Ask about `validators` (optional) offer to create one or skip.
93
72
 
94
- If any conflict is found, present it to the user:
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:
95
74
 
96
75
  > The new law `<new-id>` may conflict with existing law `<existing-id>`:
97
76
  > - New: <summary of new law>
@@ -104,66 +83,77 @@ If any conflict is found, present it to the user:
104
83
  > 3. Rephrase the new law to avoid the conflict
105
84
  > 4. Cancel
106
85
 
107
- ### 4. Refine with the user
86
+ ### 2. Plan
108
87
 
109
- 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.
110
89
 
111
- > Here's the draft law:
112
- >
113
- > ## <law-id>
114
- >
115
- > <law content>
116
- >
117
- > Does this capture what you want, or should we adjust the wording?
90
+ ### 3. Confirm
118
91
 
119
- Iterate until the user is happy.
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.
120
93
 
121
- ### 5. Validate the draft
94
+ ### 4. Build
122
95
 
123
- 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.
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.
124
97
 
125
- 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.
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>" }`
126
101
 
127
- ### 6. Create the file
102
+ Call:
128
103
 
129
- Pick the target. The user has already chosen scope in step 1 — translate that into the `target` argument:
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
+ ```
130
115
 
131
- - Global `target: { kind: "global", file: "<file-name>.md" }` (lives at `foundry/laws/<file-name>.md`).
132
- - Type-specific → `target: { kind: "type-specific", typeId: "<artefact-type>" }` (lives at `foundry/artefacts/<typeId>/laws.md`).
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.
133
117
 
134
- Then call:
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.
135
119
 
136
- ```
137
- foundry_config_add_law({
138
- id: "<id>",
139
- name: "<name>",
140
- description: "<description>",
141
- passing: "<passing>",
142
- failing: "<failing>",
143
- target: { kind: "global", file: "<file-name>.md" } // OR
144
- { kind: "type-specific", typeId: "<artefact-type>" }
145
- })
146
- ```
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.
147
121
 
148
- The tool:
122
+ ### 5. Editing existing laws (prose or validators)
149
123
 
150
- - re-validates the body (TOCTOU);
151
- - writes the law file at the path determined by `target`;
152
- - produces one git commit on the current `config/*` branch.
124
+ When the user wants to modify an existing law — whether updating the prose description or adding/changing validators — use this flow:
153
125
 
154
- The tool appends to an existing `laws.md` automatically when the
155
- new law id is not already present. It only errors when
156
- a law with the same id is already in the file — in that case use
157
- `foundry_config_edit_law({ id: "<law-id>", description: "<updated>", passing: "<updated>", failing: "<updated>" })`
158
- to modify the existing law in place.
126
+ #### 5a. Read the existing law
159
127
 
160
- Show the user the resulting commit hash from the response.
128
+ Call `foundry_config_read_law({ id: "<law-id>" })` to fetch the full markdown content.
129
+
130
+ #### 5b. Refine with the user
131
+
132
+ Show the current content and ask what should change. Iterate on the updated markdown until the user is satisfied.
161
133
 
162
- ### 7. Verify uniqueness
134
+ #### 5c. Drift mitigation: Prose changes
163
135
 
164
- 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.
136
+ **If the user is modifying the law's prose description**, insert this prompt before updating:
137
+
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.
139
+
140
+ Then proceed with the update.
141
+
142
+ #### 5d. Drift mitigation: Validator changes
143
+
144
+ **If the user is adding or modifying a validator**, insert this prompt before updating:
145
+
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.
147
+
148
+ Then proceed with the update.
149
+
150
+ #### 5e. Apply the update
151
+
152
+ Call `foundry_config_edit_law({ id: "<law-id>", description: "<updated>", passing: "<updated>", failing: "<updated>", validators: [...] })` with the full updated fields.
153
+
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.
165
155
 
166
- ### 7a. Validator contract
156
+ ### 6. Validator contract
167
157
 
168
158
  A law's `validators:` entries declare CLI commands that `quench` runs
169
159
  during a cycle. The plugin parses each command's stdout as **JSONL**
@@ -268,40 +258,6 @@ validators:
268
258
  failure-means: The artefact file does not contain exactly three non-empty lines.
269
259
  ~~~
270
260
 
271
- ### 8. Editing existing laws (prose or validators)
272
-
273
- When the user wants to modify an existing law — whether updating the prose description or adding/changing validators — use this flow:
274
-
275
- #### 8a. Read the existing law
276
-
277
- Call `foundry_config_read_law({ id: "<law-id>" })` to fetch the full markdown content.
278
-
279
- #### 8b. Refine with the user
280
-
281
- Show the current content and ask what should change. Iterate on the updated markdown until the user is satisfied.
282
-
283
- #### 8c. Drift mitigation: Prose changes
284
-
285
- **If the user is modifying the law's prose description**, insert this prompt before updating:
286
-
287
- > 🔍 **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.
288
-
289
- Then proceed with the update.
290
-
291
- #### 8d. Drift mitigation: Validator changes
292
-
293
- **If the user is adding or modifying a validator**, insert this prompt before updating:
294
-
295
- > 🔍 **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.
296
-
297
- Then proceed with the update.
298
-
299
- #### 8e. Apply the update
300
-
301
- Call `foundry_config_edit_law({ id: "<law-id>", description: "<updated>", passing: "<updated>", failing: "<updated>", validators: [...] })` with the full updated fields.
302
-
303
- 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.
304
-
305
261
  ## What you do NOT do
306
262
 
307
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