opencode-gbuild 0.4.0 → 0.6.0
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/README.md +59 -41
- package/agents/gbuild-auditor.md +1 -1
- package/agents/gbuild-reviewer.md +17 -10
- package/cypher/complete.cypher +23 -0
- package/cypher/dispatch.cypher +13 -0
- package/cypher/feature.cypher +21 -0
- package/cypher/node.cypher +39 -0
- package/cypher/record-review.cypher +17 -0
- package/cypher/schema.cypher +45 -0
- package/cypher/set-status.cypher +11 -0
- package/cypher/status.cypher +33 -0
- package/cypher/validate.cypher +105 -0
- package/package.json +2 -2
- package/reference/checklist.md +16 -16
- package/reference/cypher.md +102 -0
- package/reference/failure-policies.md +6 -6
- package/reference/graph-format.md +148 -172
- package/reference/shapes.md +10 -9
- package/skills/plan/SKILL.md +113 -99
- package/skills/pr/SKILL.md +5 -3
- package/skills/review/SKILL.md +15 -7
- package/skills/run/SKILL.md +97 -56
- package/skills/status/SKILL.md +35 -45
- package/templates/example.cypher +57 -0
- package/templates/graph.json.lock +0 -0
- package/scripts/graph.py +0 -231
- package/scripts/test_graph.py +0 -379
- package/scripts/validate_format.py +0 -369
- package/templates/graph.json +0 -110
package/skills/plan/SKILL.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Decomposes a feature into a real dependency graph in .gbuild/<feature>/
|
|
2
|
+
description: Decomposes a feature into a real dependency graph in the gbuild CypherLite store (.gbuild/<feature>/db) — nodes with typed field contracts, mandatory concrete acceptance criteria, and edges that pass the cut test. Use when starting new gbuild work, before /gbuild:run.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
Plan the work described in `$ARGUMENTS` as a graph.
|
|
@@ -11,9 +11,11 @@ skill: `/gbuild:run <slug>` once — it iterates waves until the graph completes
|
|
|
11
11
|
`/gbuild:review <slug>`; if it finds issues, reopen with `/gbuild:plan <slug> --add "<fix>"` and
|
|
12
12
|
`/gbuild:run` again; if clean, `/gbuild:pr <slug>`.
|
|
13
13
|
|
|
14
|
-
Read `${CLAUDE_PLUGIN_ROOT}/reference/graph-format.md`
|
|
15
|
-
`${CLAUDE_PLUGIN_ROOT}/reference/
|
|
16
|
-
`${CLAUDE_PLUGIN_ROOT}/reference/
|
|
14
|
+
Read `${CLAUDE_PLUGIN_ROOT}/reference/graph-format.md` (the normative graph model) and
|
|
15
|
+
`${CLAUDE_PLUGIN_ROOT}/reference/cypher.md` (how to talk to the store) before doing anything, and run
|
|
16
|
+
its version check. `${CLAUDE_PLUGIN_ROOT}/reference/shapes.md`,
|
|
17
|
+
`${CLAUDE_PLUGIN_ROOT}/reference/failure-policies.md`, and `${CLAUDE_PLUGIN_ROOT}/reference/cost-model.md`
|
|
18
|
+
inform the choices below. `${CLAUDE_PLUGIN_ROOT}/reference/checklist.md` is the self-check at the end.
|
|
17
19
|
|
|
18
20
|
## Mode
|
|
19
21
|
|
|
@@ -22,7 +24,7 @@ Read `${CLAUDE_PLUGIN_ROOT}/reference/graph-format.md` before doing anything —
|
|
|
22
24
|
| a description, link, or file path | **Chart** — new feature |
|
|
23
25
|
| an existing feature slug with `--add "<req>"` | **Reopen** |
|
|
24
26
|
|
|
25
|
-
A bare slug with no `.gbuild/<slug
|
|
27
|
+
A bare slug with no `.gbuild/<slug>/db/` is a description, not a slug — chart it.
|
|
26
28
|
|
|
27
29
|
## Chart
|
|
28
30
|
|
|
@@ -30,7 +32,7 @@ A bare slug with no `.gbuild/<slug>/` is a description, not a slug — chart it.
|
|
|
30
32
|
|
|
31
33
|
Derive the feature slug from `$ARGUMENTS`: kebab-case, ≤4 words, names the outcome not the mechanism
|
|
32
34
|
(`oauth-device-flow`, not `add-some-auth-stuff`). It's the `.gbuild/<slug>/` directory name and the
|
|
33
|
-
`
|
|
35
|
+
`Feature` node's `feature` property — immutable once charted.
|
|
34
36
|
|
|
35
37
|
Then get onto a branch for it, so `run`'s commits land somewhere isolated:
|
|
36
38
|
|
|
@@ -44,9 +46,9 @@ Report the branch. Everything below happens on it.
|
|
|
44
46
|
|
|
45
47
|
### 2. Analyse the codebase
|
|
46
48
|
|
|
47
|
-
Read the project manifest(s), directory structure, `README.md`, and
|
|
48
|
-
|
|
49
|
-
say so and ask.
|
|
49
|
+
Read the project manifest(s), directory structure, `README.md`, and — for related in-flight work — the
|
|
50
|
+
`Feature` of every existing store (`feature.cypher` against each `.gbuild/*/db`, one at a time). Resolve
|
|
51
|
+
file paths or URLs in `$ARGUMENTS`; if a reference fails to load, say so and ask.
|
|
50
52
|
|
|
51
53
|
### 3. Validate and explore
|
|
52
54
|
|
|
@@ -77,8 +79,8 @@ the survey when there's only one real way — don't perform thoroughness for its
|
|
|
77
79
|
a `research`-typed GbuildNode in the first wave — `plan` charts it, `run` executes it. `plan` does
|
|
78
80
|
not run prototypes inline (the "Plan, don't do" rule below). The one exception: a check so cheap it
|
|
79
81
|
finishes in a single tool call (grep, read a file, check an installed version) — do that inline and
|
|
80
|
-
note the result. A prototype worth charting names the specific question it answers in its
|
|
81
|
-
|
|
82
|
+
note the result. A prototype worth charting names the specific question it answers in its `OUTPUT`
|
|
83
|
+
field, and its `acceptance` is the answer to that question.
|
|
82
84
|
|
|
83
85
|
### 4. Name the destination
|
|
84
86
|
|
|
@@ -87,108 +89,102 @@ done. Do not proceed until it's that sharp; everything past it goes in `out_of_s
|
|
|
87
89
|
|
|
88
90
|
### 5. Decompose into nodes, not steps
|
|
89
91
|
|
|
90
|
-
List the real pieces of work. For each pair, apply the **cut test** (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
Classify each cluster's shape per `${CLAUDE_PLUGIN_ROOT}/reference/shapes.md` (chain / diamond / router /
|
|
96
|
-
A controlled cycle needs its round cap and dedup rule decided now, not left to `run`
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
-
|
|
102
|
-
|
|
103
|
-
- **`
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
- `
|
|
118
|
-
- `slug` — filename-safe, kebab-case, immutable once created. This is what skills and checkpoint files
|
|
119
|
-
key on; it's how nodes are referred to in anything the user reads.
|
|
120
|
-
- `type` — `research | decision | code | test | verify | chore`. Set both the lowercase `type` property
|
|
121
|
-
and the matching PascalCase label (`Code`, `Research`, …).
|
|
122
|
-
- `contract.input` / `contract.output` — structured shapes, not prose. A downstream node's `input`
|
|
123
|
-
should be able to reference an upstream node's `output` field directly.
|
|
124
|
-
- `acceptance` — **mandatory, non-empty, concrete.** No vague adjectives ("looks correct", "works
|
|
125
|
-
well"). A criterion a fresh context with no other information couldn't check is not concrete enough.
|
|
126
|
-
Rewrite it until it names a file, a shape, a value, or a command's result.
|
|
127
|
-
- `verify` — only set when this node needs something *beyond* the standard `gbuild-reviewer` pass
|
|
128
|
-
(adversarial check, fact-check, human approval). Usually `null`.
|
|
129
|
-
- `failure_policy` — pick per `${CLAUDE_PLUGIN_ROOT}/reference/failure-policies.md`, don't default everything to `retry`.
|
|
130
|
-
- `model_tier` — `strong` only where judgement, not throughput, is the bottleneck
|
|
131
|
-
(`${CLAUDE_PLUGIN_ROOT}/reference/cost-model.md`).
|
|
132
|
-
|
|
133
|
-
Wire each dependency as a `DEPENDS_ON` relationship (not a `dependencies` array on the node), and each
|
|
134
|
-
criterion a node covers as a `SATISFIES` relationship (not a `satisfies` array). Set `next_node_id` and
|
|
135
|
-
`next_rel_id` to `max(id)+1` for each kind. `${CLAUDE_PLUGIN_ROOT}/templates/graph.json` is a complete worked example.
|
|
92
|
+
List the real pieces of work. For each pair, apply the **cut test** (`graph-format.md`): does one
|
|
93
|
+
actually read the other's output? If no, they're independent — same wave, not a chain. This is the step
|
|
94
|
+
hone-ai v1 skipped, and the whole reason gbuild exists: state the true dependency structure, don't
|
|
95
|
+
default to the order you thought of things in.
|
|
96
|
+
|
|
97
|
+
Classify each cluster's shape per `${CLAUDE_PLUGIN_ROOT}/reference/shapes.md` (chain / diamond / router /
|
|
98
|
+
controlled cycle). A controlled cycle needs its round cap and dedup rule decided now, not left to `run`
|
|
99
|
+
to invent.
|
|
100
|
+
|
|
101
|
+
For each GbuildNode decide (full model in `graph-format.md`):
|
|
102
|
+
|
|
103
|
+
- `slug` — kebab-case, immutable; what skills and the store key on. `title` — what the user reads.
|
|
104
|
+
- `type` — `research | decision | code | test | verify | chore`, plus the matching PascalCase label.
|
|
105
|
+
- **`OUTPUT` fields** — every node declares at least one, each with a precise `shape`
|
|
106
|
+
(`<integer>`, `<list of changed file paths>`, `<commit sha>`). Values will be scalars or lists of
|
|
107
|
+
scalars; for anything nested, the shape says it is a JSON-encoded string.
|
|
108
|
+
- **`INPUT` fields** — one per value the node reads. If it comes from another node, wire it
|
|
109
|
+
`FROM` that node's `OUTPUT` field and add the `DEPENDS_ON`. If it comes from the codebase or the
|
|
110
|
+
environment, leave it without `FROM` and say where in its `shape`. The cut test is now concrete:
|
|
111
|
+
a `DEPENDS_ON` exists exactly when the node reads one of the other's outputs.
|
|
112
|
+
- `acceptance` — **mandatory, non-empty, concrete.** No vague adjectives. A criterion a fresh context
|
|
113
|
+
with no other information couldn't check is not concrete enough — rewrite it until it names a file, a
|
|
114
|
+
shape, a value, or a command's result.
|
|
115
|
+
- `verify` — only when the node needs something *beyond* the standard `gbuild-reviewer` pass. Usually
|
|
116
|
+
omitted.
|
|
117
|
+
- `failure_policy` — per `${CLAUDE_PLUGIN_ROOT}/reference/failure-policies.md`, don't default everything
|
|
118
|
+
to `retry`. `model_tier` — `strong` only where judgement, not throughput, is the bottleneck.
|
|
119
|
+
- `status: 'pending'` — every new node starts pending.
|
|
136
120
|
|
|
137
121
|
### 6. Write the global acceptance bar
|
|
138
122
|
|
|
139
|
-
The feature-level bar is one `Acceptance` node per bullet
|
|
140
|
-
|
|
141
|
-
|
|
123
|
+
The feature-level bar is one `Acceptance` node per bullet (`id` `a-1`, `a-2`, …), each linked
|
|
124
|
+
`(:Feature)-[:HAS_ACCEPTANCE]->(:Acceptance)`. Every bullet must end up covered by at least one node's
|
|
125
|
+
`SATISFIES` edge — the validator enforces it.
|
|
142
126
|
|
|
143
127
|
### 7. Self-check against the checklist
|
|
144
128
|
|
|
145
|
-
Walk every item in `${CLAUDE_PLUGIN_ROOT}/reference/checklist.md` against the graph you
|
|
146
|
-
annotate around a failing item.
|
|
129
|
+
Walk every item in `${CLAUDE_PLUGIN_ROOT}/reference/checklist.md` against the graph you designed. Fix the
|
|
130
|
+
design, don't annotate around a failing item.
|
|
147
131
|
|
|
148
|
-
### 8.
|
|
132
|
+
### 8. Create the store and write the graph
|
|
149
133
|
|
|
150
|
-
|
|
134
|
+
Create the store exactly as `reference/cypher.md` § Creating a store shows (`mkdir`, `schema.cypher` with
|
|
135
|
+
`--snapshot-format json`, the `db/.gitignore`).
|
|
136
|
+
|
|
137
|
+
Then write the whole graph as **one** Cypher script, piped through a quoted heredoc.
|
|
138
|
+
`${CLAUDE_PLUGIN_ROOT}/templates/example.cypher` is a complete worked example — follow its structure:
|
|
139
|
+
`.begin`, a single statement of `CREATE` clauses (so variables like `a1` or `a_value` stay in scope for
|
|
140
|
+
the edges), `.commit`, `.checkpoint`.
|
|
151
141
|
|
|
152
142
|
```
|
|
153
|
-
|
|
143
|
+
cypherlite .gbuild/<slug>/db <<'CYPHER'
|
|
144
|
+
.begin
|
|
145
|
+
CREATE (f:Feature {feature: '<slug>', destination: '...', context: '...', out_of_scope: ['...']})
|
|
146
|
+
CREATE (a1:Acceptance {id: 'a-1', text: '...'})
|
|
147
|
+
CREATE (f)-[:HAS_ACCEPTANCE]->(a1)
|
|
148
|
+
CREATE (n:GbuildNode:Code {slug: '...', title: '...', type: 'code', acceptance: ['...'],
|
|
149
|
+
failure_policy: 'repair', model_tier: 'cheap', status: 'pending'})
|
|
150
|
+
CREATE (n)-[:OUTPUT]->(n_out:Field {name: '...', shape: '<...>'})
|
|
151
|
+
...
|
|
152
|
+
CREATE (m)-[:DEPENDS_ON]->(n)
|
|
153
|
+
CREATE (m)-[:INPUT]->(:Field {name: '...', shape: '<...>'})-[:FROM]->(n_out)
|
|
154
|
+
CREATE (m)-[:SATISFIES]->(a1);
|
|
155
|
+
.commit
|
|
156
|
+
.checkpoint
|
|
157
|
+
CYPHER
|
|
154
158
|
```
|
|
155
159
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
relationship types, id/counter invariants, acyclicity, and coverage. **Run it after every change** —
|
|
159
|
-
initial write, reopen, any hand-edit, any fix-up — before doing anything else with the file.
|
|
160
|
+
A constraint violation (`ConstraintValidationFailed`: a missing property, a wrong type, a duplicate
|
|
161
|
+
slug) fails the transaction and writes nothing — fix the script and run it again.
|
|
160
162
|
|
|
161
|
-
|
|
163
|
+
### 9. Validate
|
|
162
164
|
|
|
163
165
|
```
|
|
164
|
-
|
|
166
|
+
cypherlite .gbuild/<slug>/db -json < ${CLAUDE_PLUGIN_ROOT}/cypher/validate.cypher
|
|
165
167
|
```
|
|
166
168
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
+
`[]` means valid. Every row is a violation (`check`, `detail`): fix it with Cypher — a `.begin` …
|
|
170
|
+
`.commit` … `.checkpoint` script of `MATCH … SET/CREATE/DELETE` — and re-run until it prints `[]`. Never
|
|
171
|
+
hand off or commit a graph that fails validation, and never edit `graph.json` directly.
|
|
172
|
+
|
|
173
|
+
Then confirm run-readiness:
|
|
169
174
|
|
|
170
175
|
```
|
|
171
|
-
cypherlite .gbuild/<slug>/
|
|
176
|
+
cypherlite .gbuild/<slug>/db -json < ${CLAUDE_PLUGIN_ROOT}/cypher/status.cypher
|
|
172
177
|
```
|
|
173
178
|
|
|
174
|
-
|
|
175
|
-
requirement — `validate_format.py` already cross-checks with it when present and passes without it,
|
|
176
|
-
and the user should never be asked to install it.
|
|
177
|
-
|
|
178
|
-
### 9. Fire research nodes
|
|
179
|
-
|
|
180
|
-
For each `research`-typed node in the initial wave, dispatch a subagent **in parallel** (one message,
|
|
181
|
-
multiple `Agent` calls). Give each the node's `contract.input`, `acceptance`, and enough context to
|
|
182
|
-
work independently. Each writes its `output` to `.gbuild/<slug>/nodes/<id>.json` directly (`status:
|
|
183
|
-
completed`) — these still get a `gbuild-reviewer` pass before `run` will treat them as satisfying
|
|
184
|
-
anyone's dependency, same as every other node type.
|
|
179
|
+
The `wave` column is the decomposition; rows with `state: frontier` are what `run` dispatches first.
|
|
185
180
|
|
|
186
181
|
### 10. Commit and stop
|
|
187
182
|
|
|
188
|
-
Commit `.gbuild/<slug>/` unless the repo ignores it (`git check-ignore -q .gbuild/`; if true, don't
|
|
189
|
-
|
|
183
|
+
Commit `.gbuild/<slug>/` unless the repo ignores it (`git check-ignore -q .gbuild/`; if true, don't stage
|
|
184
|
+
anything under it). The store's own `.gitignore` limits that to `db/graph.json` and `db/.gitignore`.
|
|
185
|
+
Message: `<slug>: chart graph`.
|
|
190
186
|
|
|
191
|
-
Report the branch, the
|
|
187
|
+
Report the branch, the waves, and the frontier. Close with `next: /gbuild:run <slug>`.
|
|
192
188
|
|
|
193
189
|
## Reopen
|
|
194
190
|
|
|
@@ -196,22 +192,40 @@ Report the branch, the wave decomposition, and the frontier. Close with `next: /
|
|
|
196
192
|
|
|
197
193
|
0. Check out the feature's existing branch if you're not on it. Never chart a reopen onto a different
|
|
198
194
|
branch than the one the graph was charted on.
|
|
199
|
-
1.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
195
|
+
1. Read the current graph (`status.cypher`, and `node.cypher` for any node the requirement touches).
|
|
196
|
+
2. Design the delta: a new `Acceptance` node (next `a-` id) linked from the `Feature`, and whatever new
|
|
197
|
+
GbuildNodes it needs, with their `Field`s. A new node may depend on an already-completed one — wire
|
|
198
|
+
its `INPUT` `FROM` that node's `OUTPUT` like any other; its value is already recorded. Re-run the
|
|
199
|
+
checklist against the delta.
|
|
200
|
+
3. Write it as one script that `MATCH`es what it connects to and `CREATE`s the rest:
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
cypherlite .gbuild/<slug>/db <<'CYPHER'
|
|
204
|
+
.begin
|
|
205
|
+
MATCH (f:Feature), (up:GbuildNode {slug: '<existing-slug>'})-[:OUTPUT]->(up_out:Field {name: '<field>'})
|
|
206
|
+
CREATE (f)-[:HAS_ACCEPTANCE]->(a:Acceptance {id: 'a-3', text: '...'})
|
|
207
|
+
CREATE (n:GbuildNode:Code {slug: '...', ..., status: 'pending'})
|
|
208
|
+
CREATE (n)-[:DEPENDS_ON]->(up)
|
|
209
|
+
CREATE (n)-[:INPUT]->(:Field {name: '...', shape: '<...>'})-[:FROM]->(up_out)
|
|
210
|
+
CREATE (n)-[:OUTPUT]->(:Field {name: '...', shape: '<...>'})
|
|
211
|
+
CREATE (n)-[:SATISFIES]->(a);
|
|
212
|
+
.commit
|
|
213
|
+
.checkpoint
|
|
214
|
+
CYPHER
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
4. **Re-run `validate.cypher`** until it prints `[]`, then `status.cypher`. Commit
|
|
218
|
+
(`<slug>: reopen graph — <what was added>`), report the new frontier.
|
|
207
219
|
|
|
208
220
|
If the requirement needs no new nodes (an existing node's contract already covers it), say so and stop
|
|
209
221
|
— don't manufacture graph churn.
|
|
210
222
|
|
|
211
223
|
## Rules
|
|
212
224
|
|
|
213
|
-
- **Plan, don't do.** Nodes here get *defined*, not executed — even `research` nodes
|
|
214
|
-
|
|
225
|
+
- **Plan, don't do.** Nodes here get *defined*, not executed — even `research` nodes. They land in the
|
|
226
|
+
first wave and `run` dispatches them.
|
|
227
|
+
- **The store is only touched through `cypherlite`**, from this skill, one command at a time
|
|
228
|
+
(`reference/cypher.md`).
|
|
215
229
|
- **Acceptance criteria are the bar, not a formality.** A node with vague acceptance is a node
|
|
216
230
|
`gbuild-reviewer` can't actually check — that's a planning failure, not something to fix later.
|
|
217
|
-
- **Refer to nodes by title in anything the user reads.**
|
|
231
|
+
- **Refer to nodes by title in anything the user reads.** Slugs are for the graph, not the conversation.
|
package/skills/pr/SKILL.md
CHANGED
|
@@ -12,7 +12,9 @@ This skill MUST run in the **main conversation context**. It MUST NOT be invoked
|
|
|
12
12
|
|
|
13
13
|
`$ARGUMENTS` is free-form text: an optional feature slug and an optional `--max-rounds N` flag.
|
|
14
14
|
|
|
15
|
-
- **slug**: the first token that isn't a flag. If absent, infer it — the current branch commonly ends in the slug (`plan` checks out `<prefix>/<slug>`), otherwise fall back to the
|
|
15
|
+
- **slug**: the first token that isn't a flag. If absent, infer it — the current branch commonly ends in the slug (`plan` checks out `<prefix>/<slug>`), otherwise fall back to the store whose `.gbuild/*/db/graph.json` was most recently modified. If neither resolves, leave `<slug>` unresolved (the auto-fix step degrades gracefully — see Step 4).
|
|
16
|
+
|
|
17
|
+
When `<slug>` resolved, read `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md` and run its version check — every graph read below goes through `cypherlite`, one command at a time.
|
|
16
18
|
- **max_rounds**: the value of `--max-rounds N` (also accept `--max-rounds=N`). Default `3` when absent.
|
|
17
19
|
|
|
18
20
|
## Step 1: Preconditions
|
|
@@ -25,7 +27,7 @@ Verify the environment before touching the remote. Stop with a clear, actionable
|
|
|
25
27
|
4. **Not on base.** Get the current branch (`git branch --show-current`). If it equals `<base>`, stop — there is nothing to open a PR for.
|
|
26
28
|
5. **Clean tree.** Check for uncommitted changes (`git status --porcelain`). `/gbuild:run` commits each node's work as it goes, so the tree should be clean. If there are uncommitted changes, warn the user and ask whether to proceed (they may want to commit first).
|
|
27
29
|
6. **Commits ahead of base.** Confirm the branch has commits the base lacks (`git log <base>..HEAD --oneline`). If empty, stop — nothing to push.
|
|
28
|
-
7. **Graph finished.** When `<slug>` resolved, run `
|
|
30
|
+
7. **Graph finished.** When `<slug>` resolved, run `cypherlite .gbuild/<slug>/db -json < ${CLAUDE_PLUGIN_ROOT}/cypher/status.cypher`. If any row has `state: frontier` or `in_progress`, warn that the graph isn't finished and ask whether to open the PR anyway. If any node is `failed`, name it — a PR built on an escalated node is usually premature.
|
|
29
31
|
|
|
30
32
|
## Step 2: Determine the remote & push
|
|
31
33
|
|
|
@@ -45,7 +47,7 @@ Gather context from:
|
|
|
45
47
|
|
|
46
48
|
- Commit subjects: `git log <base>..HEAD --oneline`.
|
|
47
49
|
- File overview: `git diff <base>...HEAD --stat`.
|
|
48
|
-
- When
|
|
50
|
+
- When `<slug>` resolved: `cypherlite .gbuild/<slug>/db -json < ${CLAUDE_PLUGIN_ROOT}/cypher/feature.cypher` — the `destination`, the acceptance bar (with the nodes covering each criterion), and every node's recorded output values.
|
|
49
51
|
|
|
50
52
|
Derive a concise, conventional-commit-style title from the feature/branch and the changes (e.g. `feat(auth): add OAuth login`).
|
|
51
53
|
|
package/skills/review/SKILL.md
CHANGED
|
@@ -11,20 +11,28 @@ missed abstractions that only exist *between* nodes, which no per-node review ca
|
|
|
11
11
|
## Arguments
|
|
12
12
|
|
|
13
13
|
`$ARGUMENTS` is optional. If present, treat it as the feature slug. If absent, infer it — the current
|
|
14
|
-
branch commonly ends in the slug (`plan` checks out `<prefix>/<slug>`), otherwise fall back to the
|
|
15
|
-
|
|
14
|
+
branch commonly ends in the slug (`plan` checks out `<prefix>/<slug>`), otherwise fall back to the store
|
|
15
|
+
whose `.gbuild/*/db/graph.json` was most recently modified. Do NOT write any file — this skill outputs to
|
|
16
|
+
chat exclusively.
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
`
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
Read `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md` and run its version check. Then, one after the other,
|
|
19
|
+
run `validate.cypher` and `status.cypher` against `.gbuild/<slug>/db`. If the frontier is non-empty or
|
|
20
|
+
nodes are still `in_progress`, say the graph isn't finished and ask whether to audit anyway — auditing a
|
|
21
|
+
half-built branch produces findings that the remaining nodes were going to address.
|
|
21
22
|
|
|
22
23
|
## Run the audit
|
|
23
24
|
|
|
25
|
+
Fetch the feature context:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
cypherlite .gbuild/<slug>/db -json < ${CLAUDE_PLUGIN_ROOT}/cypher/feature.cypher
|
|
29
|
+
```
|
|
30
|
+
|
|
24
31
|
Launch the `gbuild-auditor` subagent (agents/gbuild-auditor.md — this plugin's own copy, gbuild does not
|
|
25
32
|
depend on hone-ai being installed). Pass it:
|
|
26
33
|
|
|
27
|
-
- The resolved slug and
|
|
34
|
+
- The resolved slug and the `feature.cypher` result verbatim (destination, acceptance bar with the nodes
|
|
35
|
+
covering each criterion, every node's recorded outputs) — the auditor never opens the store itself.
|
|
28
36
|
- Tell it to audit the current branch.
|
|
29
37
|
|
|
30
38
|
The sub-agent runs the full audit in its own fresh context and returns the audit as its final message.
|
package/skills/run/SKILL.md
CHANGED
|
@@ -1,99 +1,140 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Executes a gbuild graph — dispatches every ready-and-independent node in the current wave concurrently, reviews each node's output with gbuild-reviewer before
|
|
2
|
+
description: Executes a gbuild graph — dispatches every ready-and-independent node in the current wave concurrently, reviews each node's output with gbuild-reviewer before recording it complete, and resumes only the remaining frontier on re-invocation. Use after /gbuild:plan has charted the graph.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
Run `.gbuild/$ARGUMENTS/
|
|
5
|
+
Run the graph in `.gbuild/$ARGUMENTS/db` (the feature slug is `$ARGUMENTS`).
|
|
6
6
|
|
|
7
7
|
**CRITICAL: this skill must run in the main context, not inside a forked agent.** It dispatches its own
|
|
8
|
-
subagents per node; a subagent cannot itself fan out further subagents reliably.
|
|
8
|
+
subagents per node; a subagent cannot itself fan out further subagents reliably. It is also the store's
|
|
9
|
+
**only writer**: subagents never run `cypherlite` — they get what they need in their prompt and report
|
|
10
|
+
back in their final message, and this skill records it. Read `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md`
|
|
11
|
+
first and run its version check; `DB` below is `.gbuild/<feature>/db`.
|
|
9
12
|
|
|
10
13
|
## Step 0: Load and query
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
`slug` property; dependencies are `DEPENDS_ON` relationships, feature-level acceptance is `Acceptance`
|
|
14
|
-
nodes linked by `HAS_ACCEPTANCE`/`SATISFIES`). **Confirm it's well-formed first:**
|
|
15
|
+
**Confirm the graph is well-formed:**
|
|
15
16
|
|
|
16
17
|
```
|
|
17
|
-
|
|
18
|
+
cypherlite DB -json < ${CLAUDE_PLUGIN_ROOT}/cypher/validate.cypher
|
|
18
19
|
```
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
correctly. Then take the frontier:
|
|
21
|
+
Anything but `[]` → stop and report the rows; do not run a graph `plan` didn't finish correctly. Then:
|
|
22
22
|
|
|
23
23
|
```
|
|
24
|
-
|
|
24
|
+
cypherlite DB -json < ${CLAUDE_PLUGIN_ROOT}/cypher/status.cypher
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
- **Rows with `state: in_progress`** at this point are left over from an interrupted run (this skill is
|
|
28
|
+
the only writer, and it records every node before finishing). Check `git log` for commits the node's
|
|
29
|
+
agent already made, reset each to `pending` with `set-status.cypher` (`--param 'status="pending"'`) so
|
|
30
|
+
it re-dispatches, and mention it in the report.
|
|
31
|
+
- The rows with `state: frontier` are the set ready right now — not a judgement call; the query already
|
|
32
|
+
excludes anything blocked, in flight, or done.
|
|
33
|
+
- If there is no frontier and every row is `completed` or `cancelled`, the graph is done — report that
|
|
34
|
+
and stop. If there is no frontier but nodes remain incomplete, there's a stuck cluster (likely an
|
|
35
|
+
`escalate`d or `stop`ped node, now `failed`) — report what's blocking and stop.
|
|
33
36
|
|
|
34
37
|
## Step 1: Establish VCS facts
|
|
35
38
|
|
|
36
|
-
Default to `git`. `git check-ignore -q .gbuild/` tells you whether to
|
|
39
|
+
Default to `git`. `git check-ignore -q .gbuild/` tells you whether to commit the store at all.
|
|
37
40
|
|
|
38
41
|
## Step 2: Pick a backend
|
|
39
42
|
|
|
40
43
|
**Workflow tool**, if this session has opted into multi-agent orchestration (ultracode, or the user
|
|
41
|
-
asked for a workflow explicitly) — translate
|
|
44
|
+
asked for a workflow explicitly) — translate the frontier into a `pipeline()`/`parallel()` script: each
|
|
42
45
|
node is an `agent()` implement call, immediately followed by a `gbuild-reviewer` `agent()` review call
|
|
43
|
-
scoped to that node's
|
|
44
|
-
|
|
45
|
-
Controlled-cycle clusters become a bounded `while` loop per `${CLAUDE_PLUGIN_ROOT}/reference/shapes.md`'s
|
|
46
|
-
`model_tier: strong` nodes via `opts.model` where the harness supports an override.
|
|
46
|
+
scoped to that node's outputs + `acceptance`, using `schema` for the pass/fail verdict. Code nodes
|
|
47
|
+
touching files that could conflict with a concurrent sibling get `isolation: 'worktree'`.
|
|
48
|
+
Controlled-cycle clusters become a bounded `while` loop per `${CLAUDE_PLUGIN_ROOT}/reference/shapes.md`'s
|
|
49
|
+
round cap. Route `model_tier: strong` nodes via `opts.model` where the harness supports an override. The
|
|
50
|
+
script never touches the store: collect every implement and review result, then record them from the
|
|
51
|
+
main context exactly as step 3.4 describes.
|
|
47
52
|
|
|
48
53
|
**Fallback** (default — no opt-in required, and always what step 3 below assumes): fire one `Agent`
|
|
49
|
-
tool call per node
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
## Step 3:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
54
|
+
tool call per frontier node, **all in a single message** — this is what makes the fan-out real rather
|
|
55
|
+
than claimed. Do not dispatch them one at a time across separate messages; that's exactly the serial
|
|
56
|
+
behavior this plugin replaces.
|
|
57
|
+
|
|
58
|
+
## Step 3: One wave (fallback backend)
|
|
59
|
+
|
|
60
|
+
1. **MARK.** Move the whole frontier to `in_progress` in one call and check that `dispatched` lists every
|
|
61
|
+
slug you passed:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
cypherlite DB -json --param 'slugs=["<slug>", ...]' < ${CLAUDE_PLUGIN_ROOT}/cypher/dispatch.cypher
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Then fetch each node's definition — `node.cypher` with `--param 'slug="<slug>"'`, one call per node,
|
|
68
|
+
one after the other. Its `inputs` are already resolved: each input read from another node carries
|
|
69
|
+
the upstream `value`.
|
|
70
|
+
|
|
71
|
+
2. **IMPLEMENT.** In one message, spawn one `Agent` per node. Give each the node's `slug`, `title`,
|
|
72
|
+
`type`, `inputs` (name, shape, value — or for an input with no `from`, where to find it),
|
|
73
|
+
`outputs` (name, shape), and `acceptance`. Tell it to:
|
|
74
|
+
- actually do the work — for `code`/`test`/`chore` nodes make the change in the working tree (not
|
|
75
|
+
describe it) and commit it, message `<feature>/<slug>: <what changed>`;
|
|
76
|
+
- produce a value for every output field: a scalar or a list of scalars, JSON-encoding anything
|
|
77
|
+
nested into a string;
|
|
78
|
+
- record its own UTC start and finish (`date -u +%Y-%m-%dT%H:%M:%SZ`) and end its final message with
|
|
79
|
+
a JSON object `{"started_at": "...", "completed_at": "...", "outputs": {...}}`;
|
|
80
|
+
- **not** run `cypherlite` or touch `.gbuild/`.
|
|
81
|
+
|
|
82
|
+
3. **REVIEW.** Once IMPLEMENT returns, spawn a `gbuild-reviewer` agent per node, again all in one message
|
|
83
|
+
(`agents/gbuild-reviewer.md` — this plugin's own copy, gbuild does not depend on hone-ai being
|
|
84
|
+
installed). Give it the node definition from `node.cypher`, the implementing agent's reported
|
|
85
|
+
outputs, and where the diff is. Never let the implementing agent review its own work.
|
|
86
|
+
|
|
87
|
+
4. **RECORD** — sequentially, one `cypherlite` call at a time, after the agents returned. For each node:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
cypherlite DB -json --param 'slug="<slug>"' --param 'verdict="pass"' --param 'failed_criteria=[]' \
|
|
91
|
+
< ${CLAUDE_PLUGIN_ROOT}/cypher/record-review.cypher
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
(`verdict="fail"` and the reviewer's failed criteria as `failed_criteria` on a fail.)
|
|
95
|
+
|
|
96
|
+
- **Pass** (`VERDICT: pass`): record it complete with the agent's outputs and times.
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
cypherlite DB -json --param 'slug="<slug>"' --param 'outputs={...}' \
|
|
100
|
+
--param 'started_at="<iso>"' --param 'completed_at="<iso>"' < ${CLAUDE_PLUGIN_ROOT}/cypher/complete.cypher
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Check `completed: true`. If it is `false`, `missing_outputs` names the output fields the agent didn't
|
|
104
|
+
produce — treat that as a failed review with those as the failed criteria. An `InvalidPropertyType`
|
|
105
|
+
error means an output value was a map: JSON-encode it into a string and record again.
|
|
106
|
+
- **Fail**: apply the node's `failure_policy` (`${CLAUDE_PLUGIN_ROOT}/reference/failure-policies.md`).
|
|
107
|
+
`retry`/`repair` re-dispatch implement → review (bounded: 2 attempts — `review_attempts` in
|
|
108
|
+
`status.cypher` counts them) with the reviewer's failed criteria fed back in; the node stays
|
|
109
|
+
`in_progress`. `fallback` dispatches the named alternate approach. `skip` sets it `cancelled`,
|
|
110
|
+
`escalate` sets it `failed` (its dependents stay blocked; siblings elsewhere keep going), both with
|
|
111
|
+
`set-status.cypher`. `stop` sets it `failed` and halts the entire run.
|
|
112
|
+
|
|
113
|
+
Nodes in the same wave never read each other's outputs, so true concurrent dispatch is safe by
|
|
114
|
+
construction — only the recording is serialized.
|
|
75
115
|
|
|
76
116
|
## Step 4: Next wave
|
|
77
117
|
|
|
78
|
-
|
|
79
|
-
|
|
118
|
+
If `.gbuild/` isn't ignored, commit the store: `git add .gbuild/<feature>/db` and
|
|
119
|
+
`git commit -m "<feature>: record wave <n>"`. Re-run `status.cypher`. If the wave that just finished
|
|
120
|
+
unblocked new frontier nodes, repeat step 3 for them. Keep going until there is no frontier (done, or
|
|
121
|
+
stuck — see step 0's exit conditions).
|
|
80
122
|
|
|
81
123
|
## Step 5: Report and stop
|
|
82
124
|
|
|
83
125
|
Report: which nodes ran this invocation, which passed review outright vs. needed a repair pass, what's
|
|
84
|
-
newly
|
|
126
|
+
newly on the frontier or still blocked, and any `failed` nodes needing a decision.
|
|
85
127
|
|
|
86
128
|
Close with the next step:
|
|
87
129
|
|
|
88
130
|
- **Graph fully done** (every node `completed` or `cancelled`) → say so plainly, then
|
|
89
131
|
`next: /gbuild:review <feature>` — the per-node reviews graded each node against its own contract;
|
|
90
132
|
nothing has yet looked at what the accumulated diff did to the codebase.
|
|
91
|
-
- **Work remains** (frontier non-empty, or nodes `failed
|
|
133
|
+
- **Work remains** (frontier non-empty, or nodes `failed` awaiting a decision) →
|
|
92
134
|
`next: /gbuild:status <feature>`.
|
|
93
135
|
|
|
94
136
|
## Resuming
|
|
95
137
|
|
|
96
|
-
Re-invoking `/gbuild:run <feature>` after an interruption re-runs step 0 fresh:
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
the memory.
|
|
138
|
+
Re-invoking `/gbuild:run <feature>` after an interruption re-runs step 0 fresh: completed and cancelled
|
|
139
|
+
nodes are excluded from the frontier automatically, and nodes an interrupted wave left `in_progress` are
|
|
140
|
+
reset and re-dispatched. Nothing needs to be told what already finished — the store is the memory.
|