@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.
- package/dist/.opencode/plugins/foundry-tools/config-create-tools.js +1 -1
- package/dist/.opencode/plugins/foundry-tools/config-law-tools.js +1 -1
- package/dist/CHANGELOG.md +47 -0
- package/dist/skills/add-appraiser/SKILL.md +19 -48
- package/dist/skills/add-artefact-type/SKILL.md +26 -105
- package/dist/skills/add-cycle/SKILL.md +46 -114
- package/dist/skills/add-extractor/SKILL.md +44 -48
- package/dist/skills/add-flow/SKILL.md +90 -23
- package/dist/skills/add-law/SKILL.md +78 -105
- package/dist/skills/add-memory-edge-type/SKILL.md +56 -27
- package/dist/skills/add-memory-entity-type/SKILL.md +59 -40
- package/dist/skills/change-embedding-model/SKILL.md +24 -14
- package/dist/skills/drop-memory-edge-type/SKILL.md +20 -12
- package/dist/skills/drop-memory-entity-type/SKILL.md +22 -14
- package/dist/skills/init-memory/SKILL.md +45 -41
- package/dist/skills/rename-memory-edge-type/SKILL.md +17 -8
- package/dist/skills/rename-memory-entity-type/SKILL.md +17 -9
- package/dist/skills/reset-memory/SKILL.md +18 -9
- package/package.json +1 -1
|
@@ -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
|
-
##
|
|
11
|
+
## Foundry Agent Preflight
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
If you are clearly operating as the Foundry agent, continue.
|
|
14
14
|
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
33
|
+
Do not tell the user to call branch tools directly.
|
|
39
34
|
|
|
40
|
-
|
|
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).
|
|
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.
|
|
55
|
+
### 2. Plan
|
|
51
56
|
|
|
52
|
-
Summarise the proposed extractor back to the user and
|
|
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
|
|
62
|
+
> - timeout: 60s
|
|
58
63
|
> - brief: "Walks the Java source tree with tree-sitter-java…"
|
|
59
64
|
>
|
|
60
|
-
>
|
|
65
|
+
> Does this capture the extractor correctly?
|
|
61
66
|
|
|
62
|
-
### 3.
|
|
67
|
+
### 3. Confirm
|
|
63
68
|
|
|
64
|
-
|
|
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.
|
|
71
|
+
### 4. Build
|
|
67
72
|
|
|
68
|
-
|
|
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
|
-
|
|
107
|
+
#### Post-Build — compose into a cycle
|
|
97
108
|
|
|
98
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
131
|
+
> Build of `<piece>` failed: `<error>`. Retry, skip this piece, or abort?
|
|
65
132
|
|
|
66
|
-
|
|
133
|
+
Do not silently skip or auto-resolve.
|
|
67
134
|
|
|
68
|
-
|
|
135
|
+
### 5. Build the flow
|
|
69
136
|
|
|
70
|
-
|
|
137
|
+
After all dependencies are built, create the flow itself:
|
|
71
138
|
|
|
72
|
-
|
|
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>" })
|
|
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
|
-
|
|
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
|
|
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
|
-
###
|
|
37
|
+
### Context object
|
|
38
38
|
|
|
39
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
48
|
+
### 1. Understand
|
|
48
49
|
|
|
49
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
86
|
+
### 2. Plan
|
|
91
87
|
|
|
92
|
-
Present
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
>
|
|
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
|
-
|
|
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.
|
|
122
|
+
### 5. Editing existing laws (prose or validators)
|
|
105
123
|
|
|
106
|
-
|
|
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
|
-
|
|
128
|
+
Call `foundry_config_read_law({ id: "<law-id>" })` to fetch the full markdown content.
|
|
109
129
|
|
|
110
|
-
|
|
130
|
+
#### 5b. Refine with the user
|
|
111
131
|
|
|
112
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
144
|
+
**If the user is adding or modifying a validator**, insert this prompt before updating:
|
|
132
145
|
|
|
133
|
-
|
|
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
|
-
|
|
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
|
-
|
|
150
|
+
#### 5e. Apply the update
|
|
144
151
|
|
|
145
|
-
|
|
152
|
+
Call `foundry_config_edit_law({ id: "<law-id>", description: "<updated>", passing: "<updated>", failing: "<updated>", validators: [...] })` with the full updated fields.
|
|
146
153
|
|
|
147
|
-
|
|
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
|
-
###
|
|
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
|
-
##
|
|
9
|
+
## Foundry Agent Preflight
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
If you are clearly operating as the Foundry agent, continue.
|
|
12
12
|
|
|
13
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|