opencode-gbuild 0.7.0 → 0.8.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 +10 -10
- package/agents/gbuild-auditor.md +1 -1
- package/agents/gbuild-reviewer.md +1 -1
- package/cypher/attention.cypher +1 -1
- package/cypher/dispatch.cypher +1 -2
- package/cypher/feature.cypher +1 -1
- package/cypher/node.cypher +1 -1
- package/cypher/progress.cypher +1 -1
- package/cypher/record.cypher +1 -2
- package/cypher/schema.cypher +1 -2
- package/cypher/set-status.cypher +1 -2
- package/cypher/status.cypher +1 -1
- package/cypher/validate.cypher +1 -1
- package/package.json +1 -1
- package/reference/checklist.md +1 -1
- package/reference/cypher.md +48 -29
- package/reference/graph-format.md +14 -14
- package/reference/queries.md +3 -3
- package/skills/plan/SKILL.md +25 -32
- package/skills/pr/SKILL.md +7 -5
- package/skills/review/SKILL.md +8 -7
- package/skills/run/SKILL.md +16 -16
- package/skills/status/SKILL.md +10 -9
- package/templates/example.cypher +1 -2
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ OpenCode (same order, kebab-case names):
|
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
- **`plan`** creates the feature branch in its own git worktree and charts the feature into a
|
|
101
|
-
CypherLite graph store
|
|
101
|
+
machine-local CypherLite graph store (`<git-common-dir>/gbuild/<feature>/db`) — `Feature`,
|
|
102
102
|
`Acceptance`, and `GbuildNode` nodes, each node's contract as `INPUT`/`OUTPUT` `Field` nodes, and
|
|
103
103
|
`FROM` edges carrying data from one node's output to the next node's input. Every dependency edge
|
|
104
104
|
passes the cut test — and because data flow is explicit, the validator checks it; every node has
|
|
@@ -185,7 +185,7 @@ decision is wanted; neither guesses.
|
|
|
185
185
|
|
|
186
186
|
## Runtime
|
|
187
187
|
|
|
188
|
-
gbuild **requires the [CypherLite](https://github.com/neo4j-labs/cypherlite) CLI**, 0.
|
|
188
|
+
gbuild **requires the [CypherLite](https://github.com/neo4j-labs/cypherlite) CLI**, 0.12.0 or newer:
|
|
189
189
|
|
|
190
190
|
```bash
|
|
191
191
|
curl -sSfL https://neo4j-labs.github.io/cypherlite/install.sh | bash
|
|
@@ -193,12 +193,12 @@ curl -sSfL https://neo4j-labs.github.io/cypherlite/install.sh | bash
|
|
|
193
193
|
|
|
194
194
|
Every skill reads and writes the graph with `cypherlite` and nothing else — there is no Python and no
|
|
195
195
|
direct JSON editing. The plugin ships the queries as `.cypher` files; skills pipe them into the store
|
|
196
|
-
(
|
|
196
|
+
(`<git-common-dir>/gbuild/<feature>/db` — machine-local, never committed):
|
|
197
197
|
|
|
198
198
|
```bash
|
|
199
|
-
cypherlite
|
|
200
|
-
cypherlite
|
|
201
|
-
cypherlite
|
|
199
|
+
cypherlite query --read-only --database <git-common-dir>/gbuild/<feature>/db --mode jsonl < plugins/gbuild/cypher/validate.cypher # format gate: no output = valid
|
|
200
|
+
cypherlite query --read-only --database <git-common-dir>/gbuild/<feature>/db --mode jsonl < plugins/gbuild/cypher/progress.cypher # one row per wave: counts + open nodes
|
|
201
|
+
cypherlite query --read-only "MATCH (n:GbuildNode {status: 'failed'}) RETURN n.slug" --database <git-common-dir>/gbuild/<feature>/db --mode jsonl # anything else
|
|
202
202
|
```
|
|
203
203
|
|
|
204
204
|
Reads are deliberately narrow so a run doesn't pay for the whole graph on every step: `run` claims a
|
|
@@ -233,10 +233,10 @@ plugins/gbuild/
|
|
|
233
233
|
```
|
|
234
234
|
|
|
235
235
|
State lives outside the plugin, in the project: one CypherLite store per feature at
|
|
236
|
-
|
|
237
|
-
and output values, and the full review
|
|
238
|
-
|
|
239
|
-
|
|
236
|
+
`<git-common-dir>/gbuild/<feature>/db` — machine-local, never committed and never carried by a clone.
|
|
237
|
+
It holds the plan, every node's status and output values, and the full review history; CypherLite
|
|
238
|
+
checkpoints the store on exit, so `db/graph.json` is just the engine's local snapshot. All of a
|
|
239
|
+
feature's worktrees live under
|
|
240
240
|
`.git/gbuild/<feature>/` — never in `git status`: `tree/` is the feature worktree itself, created by
|
|
241
241
|
`plan` and kept until the feature is done, and during a run each file-touching node gets a `<node>/`
|
|
242
242
|
worktree that is removed the moment its node is accepted (merged into the feature branch, in `tree/`)
|
package/agents/gbuild-auditor.md
CHANGED
|
@@ -7,7 +7,7 @@ description: Strict end-of-feature maintainability auditor for a gbuild feature
|
|
|
7
7
|
|
|
8
8
|
Unusually strict review of implementation quality, maintainability, and abstraction health. Push for **ambitious** restructurings — "code judo" moves that preserve behavior while making the code dramatically simpler, smaller, and more direct. Delete complexity; don't rearrange it.
|
|
9
9
|
|
|
10
|
-
The caller passes you the resolved feature slug, the **feature worktree** path, and the feature context it read from the gbuild store: the `destination` and the acceptance bar (each criterion with the nodes covering it). Use the context for scoping only — you are auditing the branch's code, not re-grading individual nodes (`gbuild-reviewer` already did that per node, against each node's own contract; your job is the thing no per-node pass can see — what the accumulated diff did to the codebase as a whole). The feature branch is checked out in the feature worktree: every file read, every check, and every git command runs there (`git -C <worktree> …` or with it as your working directory), never in the main tree. Do not open
|
|
10
|
+
The caller passes you the resolved feature slug, the **feature worktree** path, and the feature context it read from the gbuild store: the `destination` and the acceptance bar (each criterion with the nodes covering it). Use the context for scoping only — you are auditing the branch's code, not re-grading individual nodes (`gbuild-reviewer` already did that per node, against each node's own contract; your job is the thing no per-node pass can see — what the accumulated diff did to the codebase as a whole). The feature branch is checked out in the feature worktree: every file read, every check, and every git command runs there (`git -C <worktree> …` or with it as your working directory), never in the main tree. Do not open the gbuild store or run `cypherlite` — the caller owns the store. Do NOT write any file — output your audit as your final message exclusively.
|
|
11
11
|
|
|
12
12
|
## Run the branch's checks first
|
|
13
13
|
|
|
@@ -22,7 +22,7 @@ flag them here. Three things belong to you: the contract, the acceptance criteri
|
|
|
22
22
|
- For `code`/`test`/`chore` nodes: the git diff for this node's work (`git diff HEAD`, or
|
|
23
23
|
`git diff --staged`, or `git log -1 -p` if it already committed).
|
|
24
24
|
|
|
25
|
-
Everything you need is in your prompt — do not open
|
|
25
|
+
Everything you need is in your prompt — do not open the gbuild store or run `cypherlite`; the caller owns the
|
|
26
26
|
store and records your verdict.
|
|
27
27
|
|
|
28
28
|
## REVIEW OBJECTIVE
|
package/cypher/attention.cypher
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// in_progress claimed but not recorded; if no run is active, an interrupted wave left it
|
|
4
4
|
// blocked-by-failed pending behind a failed node, so it can never unblock on its own;
|
|
5
5
|
// `detail` = the failed nodes it waits on
|
|
6
|
-
// cypherlite
|
|
6
|
+
// cypherlite query --read-only --database <git-common-dir>/gbuild/<slug>/db --mode jsonl < cypher/attention.cypher
|
|
7
7
|
CALL {
|
|
8
8
|
MATCH (n:GbuildNode {status: 'failed'})
|
|
9
9
|
RETURN n.slug AS slug, 'failed' AS reason,
|
package/cypher/dispatch.cypher
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// external, and its `shape` says where to find it. No rows = nothing is
|
|
6
6
|
// ready (the graph is done or stuck — ask progress.cypher / attention.cypher).
|
|
7
7
|
// For a router, cancel the unselected branches with set-status.cypher first.
|
|
8
|
-
// cypherlite
|
|
8
|
+
// cypherlite query --database <git-common-dir>/gbuild/<slug>/db --mode jsonl < cypher/dispatch.cypher
|
|
9
9
|
MATCH (n:GbuildNode {status: 'pending'})
|
|
10
10
|
WHERE NOT EXISTS { MATCH (n)-[:DEPENDS_ON]->(d:GbuildNode) WHERE NOT d.status IN ['completed', 'cancelled'] }
|
|
11
11
|
SET n.status = 'in_progress'
|
|
@@ -28,4 +28,3 @@ RETURN n.slug AS slug,
|
|
|
28
28
|
RETURN {name: f.name, shape: f.shape}
|
|
29
29
|
} AS outputs
|
|
30
30
|
ORDER BY slug;
|
|
31
|
-
.checkpoint
|
package/cypher/feature.cypher
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// nodes that cover each criterion. What review hands the auditor and what pr
|
|
3
3
|
// builds the description from. Per-node output values are not included — get
|
|
4
4
|
// one node's with node.cypher if you actually need it.
|
|
5
|
-
// cypherlite
|
|
5
|
+
// cypherlite query --read-only --database <git-common-dir>/gbuild/<slug>/db --mode jsonl < cypher/feature.cypher
|
|
6
6
|
MATCH (f:Feature)
|
|
7
7
|
RETURN f.feature AS feature,
|
|
8
8
|
f.destination AS destination,
|
package/cypher/node.cypher
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// external (from the codebase / environment): its `from` and `value` are null.
|
|
4
4
|
// Used for reopen and ad-hoc inspection; run gets its definitions from
|
|
5
5
|
// dispatch.cypher instead.
|
|
6
|
-
// cypherlite
|
|
6
|
+
// cypherlite query --read-only --database <git-common-dir>/gbuild/<slug>/db --mode jsonl --param 'slug="<node-slug>"' < cypher/node.cypher
|
|
7
7
|
MATCH (n:GbuildNode {slug: $slug})
|
|
8
8
|
RETURN n.slug AS slug,
|
|
9
9
|
n.title AS title,
|
package/cypher/progress.cypher
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// that wave not yet completed or cancelled. A wave with `open: []` is done;
|
|
3
3
|
// the graph is done when every row's `open` is empty. `wave` is the longest
|
|
4
4
|
// DEPENDS_ON chain below a node (0 = no dependencies).
|
|
5
|
-
// cypherlite
|
|
5
|
+
// cypherlite query --read-only --database <git-common-dir>/gbuild/<slug>/db --mode jsonl < cypher/progress.cypher
|
|
6
6
|
MATCH (n:GbuildNode)
|
|
7
7
|
OPTIONAL MATCH p = (n)-[:DEPENDS_ON*]->()
|
|
8
8
|
WITH n, coalesce(max(length(p)), 0) AS wave
|
package/cypher/record.cypher
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// you sent. Output values must be scalars or lists of scalars — one nested
|
|
8
8
|
// value rejects the whole batch (InvalidPropertyType); JSON-encode it and
|
|
9
9
|
// resend.
|
|
10
|
-
// cypherlite
|
|
10
|
+
// cypherlite query --database <git-common-dir>/gbuild/<slug>/db --mode jsonl --param 'results=[
|
|
11
11
|
// {"slug": "a", "verdict": "pass", "failed_criteria": [], "outputs": {"value": 7},
|
|
12
12
|
// "started_at": "<iso>", "completed_at": "<iso>"},
|
|
13
13
|
// {"slug": "b", "verdict": "fail", "failed_criteria": ["<criterion>"]}
|
|
@@ -35,4 +35,3 @@ FOREACH (_ IN CASE WHEN ok THEN [1] ELSE [] END |
|
|
|
35
35
|
SET n.status = 'completed', n.started_at = r.started_at, n.completed_at = r.completed_at)
|
|
36
36
|
RETURN n.slug AS slug, attempt, review.verdict AS verdict, ok AS completed, missing AS missing_outputs
|
|
37
37
|
ORDER BY slug;
|
|
38
|
-
.checkpoint
|
package/cypher/schema.cypher
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// gbuild store schema. Run once, when plan creates the store:
|
|
2
|
-
// cypherlite
|
|
2
|
+
// cypherlite query --database <git-common-dir>/gbuild/<slug>/db --snapshot-format json < cypher/schema.cypher
|
|
3
3
|
// Everything the engine can enforce at write time lives here; the rest of the
|
|
4
4
|
// contract is checked by validate.cypher.
|
|
5
5
|
CREATE CONSTRAINT feature_name FOR (n:Feature) REQUIRE n.feature IS :: STRING;
|
|
@@ -42,4 +42,3 @@ CREATE CONSTRAINT review_verdict_exists FOR (n:Review) REQUIRE n.verdict IS NOT
|
|
|
42
42
|
CREATE CONSTRAINT review_at FOR (n:Review) REQUIRE n.at IS :: STRING;
|
|
43
43
|
CREATE CONSTRAINT review_at_exists FOR (n:Review) REQUIRE n.at IS NOT NULL;
|
|
44
44
|
CREATE CONSTRAINT review_failed_criteria FOR (n:Review) REQUIRE n.failed_criteria IS :: LIST<STRING NOT NULL>;
|
|
45
|
-
.checkpoint
|
package/cypher/set-status.cypher
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// retry/repair, stop), or `pending` (reset nodes an interrupted run left
|
|
4
4
|
// in_progress). `completed` is rejected — only record.cypher may set it, so it
|
|
5
5
|
// can require a passing review and every output value.
|
|
6
|
-
// cypherlite
|
|
6
|
+
// cypherlite query --database <git-common-dir>/gbuild/<slug>/db --mode jsonl --param 'slugs=["a","b"]' --param 'status="cancelled"' \
|
|
7
7
|
// < cypher/set-status.cypher
|
|
8
8
|
UNWIND $slugs AS s
|
|
9
9
|
MATCH (n:GbuildNode {slug: s})
|
|
@@ -11,4 +11,3 @@ WHERE $status IN ['pending', 'in_progress', 'failed', 'cancelled']
|
|
|
11
11
|
SET n.status = $status
|
|
12
12
|
RETURN n.slug AS slug, n.status AS status
|
|
13
13
|
ORDER BY slug;
|
|
14
|
-
.checkpoint
|
package/cypher/status.cypher
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// otherwise = the stored status (in_progress, completed, failed, cancelled)
|
|
5
5
|
// `wave` is the longest DEPENDS_ON chain below the node (0 = no dependencies),
|
|
6
6
|
// so nodes sharing a wave are safe to run concurrently.
|
|
7
|
-
// cypherlite
|
|
7
|
+
// cypherlite query --read-only --database <git-common-dir>/gbuild/<slug>/db --mode jsonl < cypher/status.cypher
|
|
8
8
|
MATCH (n:GbuildNode)
|
|
9
9
|
OPTIONAL MATCH p = (n)-[:DEPENDS_ON*]->()
|
|
10
10
|
WITH n, coalesce(max(length(p)), 0) AS wave
|
package/cypher/validate.cypher
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// gbuild format gate. Zero rows = valid; every row is one violation.
|
|
2
|
-
// cypherlite
|
|
2
|
+
// cypherlite query --read-only --database <git-common-dir>/gbuild/<slug>/db --mode jsonl < cypher/validate.cypher
|
|
3
3
|
// Required properties, their types and slug/acceptance-id uniqueness are
|
|
4
4
|
// engine constraints (schema.cypher) — a write that breaks them never lands.
|
|
5
5
|
// This query checks everything the engine can't: enums, label/type agreement,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "opencode-gbuild",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"description": "OpenCode plugin for gbuild — graph-native task planning and execution with concurrent fan-out, per-node review, and durable checkpoints.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
package/reference/checklist.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Ship checklist
|
|
2
2
|
|
|
3
|
-
`plan` runs this checklist against the graph it just wrote, before
|
|
3
|
+
`plan` runs this checklist against the graph it just wrote, before handing off to `run`. Any item that
|
|
4
4
|
fails means revise the graph (with Cypher), not add a caveat in prose.
|
|
5
5
|
|
|
6
6
|
1. **Risky assumptions are resolved, not deferred.** Every assumption that would invalidate nodes or
|
package/reference/cypher.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# Talking to the gbuild store
|
|
2
2
|
|
|
3
|
-
Every gbuild skill reads and writes the feature store (
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
manual; the skills that only run plugin scripts carry the short version
|
|
3
|
+
Every gbuild skill reads and writes the feature store (modelled in `reference/graph-format.md`) with the
|
|
4
|
+
`cypherlite` CLI and nothing else. `DB` throughout is the store path:
|
|
5
|
+
`<git-common-dir>/gbuild/<feature>/db` — beside the feature worktree, machine-local, never committed.
|
|
6
|
+
This file is the full operating manual; the skills that only run plugin scripts carry the short version
|
|
7
|
+
of these rules inline.
|
|
7
8
|
|
|
8
9
|
## Requirement
|
|
9
10
|
|
|
10
|
-
`cypherlite` 0.
|
|
11
|
+
`cypherlite` 0.12.0 or newer must be on PATH. Check first, in every skill:
|
|
11
12
|
|
|
12
13
|
```
|
|
13
14
|
cypherlite --version
|
|
@@ -17,42 +18,47 @@ If the command is missing, stop and tell the user gbuild needs it:
|
|
|
17
18
|
`curl -sSfL https://neo4j-labs.github.io/cypherlite/install.sh | bash`. Never fall back to reading or
|
|
18
19
|
editing `graph.json` by hand.
|
|
19
20
|
|
|
21
|
+
The floor is the ADR-0200 CLI cutover: the store path is a flag (`-d` / `--database PATH`), the first
|
|
22
|
+
positional is the Cypher statement (never the database), and piped scripts and the interactive shell
|
|
23
|
+
require the explicit `query` verb. The old path-first form — database as the first argument — hard-fails.
|
|
24
|
+
|
|
20
25
|
## One writer, one command at a time
|
|
21
26
|
|
|
22
27
|
CypherLite takes an exclusive lock on the store while a process has it open. A second process — reader
|
|
23
|
-
or writer — fails with `storage locked` (exit
|
|
28
|
+
or writer — fails with `storage locked` (exit 5). So:
|
|
24
29
|
|
|
25
30
|
- **Only the skill running in the main context runs `cypherlite` against the store.** Subagents never
|
|
26
31
|
do: give them what they need in their prompt, have them report results in their final message, and
|
|
27
32
|
record those results yourself.
|
|
28
33
|
- **Never run two `cypherlite` commands against the same store at once** — no parallel tool calls on it.
|
|
29
34
|
Fan-out is for agents, not for store access.
|
|
30
|
-
- On `storage locked
|
|
31
|
-
few seconds and retry, up to 3 times; then stop and report. Never delete
|
|
35
|
+
- On `storage locked` (exit 5), another process holds the store (another gbuild command, a REPL left
|
|
36
|
+
open). Wait a few seconds and retry, up to 3 times; then stop and report. Never delete
|
|
37
|
+
`.cypherlite.lock`.
|
|
32
38
|
|
|
33
39
|
## Invocation
|
|
34
40
|
|
|
35
41
|
Always pass `--mode jsonl`: one compact JSON object per row, one row per line, and no output at all when
|
|
36
|
-
there are no rows.
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
there are no rows. Every call is `cypherlite query [STATEMENT] --database DB …`; with no STATEMENT the
|
|
43
|
+
piped stdin is the script list. Pure reads add `--read-only`: no exit flush, a shared lock, and a
|
|
44
|
+
fail-fast on a wrong path — a read-only call never creates a missing store. Writes (schema creation,
|
|
45
|
+
dispatch, record, set-status, authored heredocs) go without.
|
|
39
46
|
|
|
40
47
|
```
|
|
41
|
-
# a plugin script
|
|
42
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
|
|
48
|
+
# a plugin read script
|
|
49
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
|
|
43
50
|
|
|
44
|
-
# a plugin script with parameters
|
|
45
|
-
cypherlite DB --mode jsonl --param 'slug="b-consume-doubled"' < ${CLAUDE_PLUGIN_ROOT}/cypher/node.cypher
|
|
51
|
+
# a plugin read script with parameters
|
|
52
|
+
cypherlite query --read-only --database DB --mode jsonl --param 'slug="b-consume-doubled"' < ${CLAUDE_PLUGIN_ROOT}/cypher/node.cypher
|
|
46
53
|
|
|
47
54
|
# an ad-hoc read — return only the columns you need, and keep a LIMIT on anything that can grow
|
|
48
|
-
cypherlite
|
|
55
|
+
cypherlite query "MATCH (n:GbuildNode {status: 'failed'}) RETURN n.slug LIMIT 20" --read-only --database DB --mode jsonl
|
|
49
56
|
|
|
50
57
|
# a write you author (plan, reopen, fixes) — quoted heredoc delimiter, so the shell expands nothing
|
|
51
|
-
cypherlite DB <<'CYPHER'
|
|
58
|
+
cypherlite query --database DB <<'CYPHER'
|
|
52
59
|
.begin
|
|
53
60
|
MATCH (n:GbuildNode {slug: 'b-consume-doubled'}) SET n.title = 'Consume the value, double it';
|
|
54
61
|
.commit
|
|
55
|
-
.checkpoint
|
|
56
62
|
CYPHER
|
|
57
63
|
```
|
|
58
64
|
|
|
@@ -66,33 +72,46 @@ CYPHER
|
|
|
66
72
|
Bare values that start with a digit — timestamps, `01-…` slugs — are rejected, so always quote.
|
|
67
73
|
- **String literals** in Cypher you author: single quotes by default; double quotes when the text
|
|
68
74
|
contains an apostrophe (`"gbuild's"`); backslash-escape (`\'`, `\"`) when it contains both.
|
|
69
|
-
- **Authored writes are atomic
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
- **Authored writes are atomic.** Wrap them in `.begin` / `.commit` — if any statement fails, the whole
|
|
76
|
+
transaction is discarded. The plugin write scripts already do. Never write `.checkpoint`: a writable
|
|
77
|
+
session checkpoints on exit by itself.
|
|
72
78
|
- **Values are scalars or lists of scalars.** CypherLite cannot store a map as a property value;
|
|
73
79
|
JSON-encode anything nested into a string.
|
|
74
80
|
- **Read the result.** The plugin write scripts are guarded and return what they actually changed.
|
|
75
81
|
Compare it with what you asked for; never assume a write landed.
|
|
76
|
-
- **
|
|
77
|
-
|
|
82
|
+
- **Check the exit code.** `0` is success (an empty result included). `5` is `storage locked` or a
|
|
83
|
+
write conflict — wait and retry as above. `6` is a rejected statement — syntax, semantic, or type
|
|
84
|
+
error, including `ConstraintValidationFailed` and writes on a `--read-only` store — read stderr, fix,
|
|
85
|
+
retry the whole transaction. `2` is a usage error — fix the invocation, not the data. `1` is any other
|
|
86
|
+
runtime failure. With `--mode jsonl` a failure also prints one JSON error envelope on stdout, after
|
|
87
|
+
any rows already written: `{"error":{"code","exit_code","kind","message","retryable"}}`.
|
|
88
|
+
- **Agent output is capped at 100 rows.** Under a detected agent harness with non-terminal stdout —
|
|
89
|
+
gbuild skills always are — a statement prints at most 100 rows, warns on stderr, and still exits `0`.
|
|
90
|
+
Keep a `LIMIT` on anything that can grow; when you genuinely need every row, pass `--max-rows 0` (or
|
|
91
|
+
set `CYPHERLITE_MAX_ROWS=0`).
|
|
78
92
|
|
|
79
93
|
## Creating a store
|
|
80
94
|
|
|
81
|
-
Only `plan` does this, once per feature
|
|
82
|
-
it just created:
|
|
95
|
+
Only `plan` does this, once per feature:
|
|
83
96
|
|
|
84
97
|
```
|
|
85
98
|
mkdir -p DB
|
|
86
|
-
cypherlite DB --snapshot-format json < ${CLAUDE_PLUGIN_ROOT}/cypher/schema.cypher
|
|
87
|
-
printf '*\n!.gitignore\n!graph.json\n' > DB/.gitignore
|
|
99
|
+
cypherlite query --database DB --snapshot-format json < ${CLAUDE_PLUGIN_ROOT}/cypher/schema.cypher
|
|
88
100
|
```
|
|
89
101
|
|
|
90
102
|
`--snapshot-format json` belongs on this first call only (it applies to an empty directory). It installs
|
|
91
|
-
the schema constraints and pins the JSON codec
|
|
103
|
+
the schema constraints and pins the JSON codec for cross-build compatibility: a parquet-enabled
|
|
104
|
+
CypherLite build defaults a new store to Parquet, and a JSON-pinned store opens in every build.
|
|
105
|
+
|
|
106
|
+
## Migrating an old store
|
|
107
|
+
|
|
108
|
+
Stores charted by gbuild ≤ 0.7.1 live at `<tree>/.gbuild/<slug>/db` and are git-tracked. Migrate with
|
|
109
|
+
`git rm -r --cached .gbuild` (commit the removal) and
|
|
110
|
+
`mv <tree>/.gbuild/<slug>/db <git-common-dir>/gbuild/<slug>/db`.
|
|
92
111
|
|
|
93
112
|
## Script catalog
|
|
94
113
|
|
|
95
|
-
All in `${CLAUDE_PLUGIN_ROOT}/cypher/`.
|
|
114
|
+
All in `${CLAUDE_PLUGIN_ROOT}/cypher/`.
|
|
96
115
|
|
|
97
116
|
| script | params | returns | used by |
|
|
98
117
|
| -------------------- | ------------------------- | -------------------------------------------------------------- | ------- |
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
This file is normative. Where a skill disagrees with this doc, this doc wins.
|
|
4
4
|
|
|
5
|
-
One CypherLite store per feature:
|
|
6
|
-
(`<git-common-dir>/gbuild/<feature>/tree
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
One CypherLite store per feature: `<git-common-dir>/gbuild/<feature>/db/`, beside the feature worktree
|
|
6
|
+
(`<git-common-dir>/gbuild/<feature>/tree/`, which `plan` creates) — untracked, machine-local, never
|
|
7
|
+
committed. `plan` creates and charts it, `run` records progress in it, and every skill reads it — **all
|
|
8
|
+
through Cypher**. No skill reads or writes `graph.json` directly; it is CypherLite's local snapshot of
|
|
9
|
+
the store, not a gbuild artifact. How to talk to the store (the single-writer rule, invocation, quoting,
|
|
10
|
+
the script catalog) is in `reference/cypher.md`.
|
|
11
11
|
|
|
12
12
|
`templates/example.cypher` is a complete worked example — a 4-node diamond — written exactly the way
|
|
13
13
|
`plan` writes a new feature.
|
|
@@ -15,17 +15,17 @@ invocation, quoting, the script catalog) is in `reference/cypher.md`.
|
|
|
15
15
|
## Store layout
|
|
16
16
|
|
|
17
17
|
```
|
|
18
|
-
|
|
19
|
-
graph.json CypherLite JSON snapshot —
|
|
20
|
-
.
|
|
21
|
-
manifest.json engine files — ignored
|
|
18
|
+
<git-common-dir>/gbuild/<feature>/db/
|
|
19
|
+
graph.json CypherLite JSON snapshot — the engine's local snapshot; gbuild never reads or writes it
|
|
20
|
+
manifest.json engine files
|
|
22
21
|
wal/
|
|
23
22
|
.cypherlite.lock
|
|
24
23
|
```
|
|
25
24
|
|
|
26
|
-
The store
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
The store lives outside every checkout: untracked, machine-local, never committed. It is created with
|
|
26
|
+
the JSON codec (`--snapshot-format json`, see `reference/cypher.md`) for cross-build compatibility: a
|
|
27
|
+
parquet-enabled CypherLite build defaults a new store to Parquet, and a JSON-pinned store opens in every
|
|
28
|
+
build.
|
|
29
29
|
|
|
30
30
|
## Nodes
|
|
31
31
|
|
|
@@ -41,7 +41,7 @@ data **and** constraints.
|
|
|
41
41
|
|
|
42
42
|
| property | type | meaning |
|
|
43
43
|
| -------------- | -------------- | ---------------------------------------------------- |
|
|
44
|
-
| `feature` | string | the slug — matches the
|
|
44
|
+
| `feature` | string | the slug — matches the `<feature>` segment of the store path, immutable |
|
|
45
45
|
| `destination` | string | one line: what is true once this is done |
|
|
46
46
|
| `context` | string | why this exists, one or two lines |
|
|
47
47
|
| `out_of_scope` | list of string | bullets, may be empty |
|
package/reference/queries.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Ad-hoc queries
|
|
2
2
|
|
|
3
3
|
The plugin scripts (`reference/cypher.md` § Script catalog) cover everything the skills do. These are for
|
|
4
|
-
the questions in between. Run them with `cypherlite
|
|
5
|
-
time — `DB` is the feature store (
|
|
6
|
-
|
|
4
|
+
the questions in between. Run them with `cypherlite query "<query>" --read-only --database DB --mode
|
|
5
|
+
jsonl`, one at a time — `DB` is the feature store (`reference/cypher.md`); return only the columns you
|
|
6
|
+
need and keep a `LIMIT` on anything that can grow.
|
|
7
7
|
|
|
8
8
|
```cypher
|
|
9
9
|
-- the whole plan with progress
|
package/skills/plan/SKILL.md
CHANGED
|
@@ -24,23 +24,24 @@ inform the choices below. `${CLAUDE_PLUGIN_ROOT}/reference/checklist.md` is the
|
|
|
24
24
|
| a description, link, or file path | **Chart** — new feature |
|
|
25
25
|
| an existing feature slug with `--add "<req>"` | **Reopen** |
|
|
26
26
|
|
|
27
|
-
A bare slug with no store is a description, not a slug — chart it. A slug's store lives
|
|
28
|
-
worktree at `<git-common-dir>/gbuild/<slug>/
|
|
29
|
-
|
|
27
|
+
A bare slug with no store is a description, not a slug — chart it. A slug's store lives beside its
|
|
28
|
+
feature worktree at `<git-common-dir>/gbuild/<slug>/db`, machine-local and never committed (a gbuild ≤ 0.7.1
|
|
29
|
+
store needs the move in `reference/cypher.md`).
|
|
30
30
|
|
|
31
31
|
## Chart
|
|
32
32
|
|
|
33
33
|
### 1. Slug, branch, and feature worktree
|
|
34
34
|
|
|
35
35
|
Derive the feature slug from `$ARGUMENTS`: kebab-case, ≤4 words, names the outcome not the mechanism
|
|
36
|
-
(`oauth-device-flow`, not `add-some-auth-stuff`). It's the
|
|
36
|
+
(`oauth-device-flow`, not `add-some-auth-stuff`). It's the `gbuild/<slug>/` directory name and the
|
|
37
37
|
`Feature` node's `feature` property — immutable once charted.
|
|
38
38
|
|
|
39
39
|
gbuild never changes the branch of the user's checkout: the feature branch lives in its own **feature
|
|
40
40
|
worktree**, so several features can be charted and run in parallel without racing each other's `HEAD`,
|
|
41
|
-
and uncommitted work in the main tree is irrelevant — there is no dirty-tree check. Resolve
|
|
42
|
-
|
|
43
|
-
`GC/gbuild/<slug
|
|
41
|
+
and uncommitted work in the main tree is irrelevant — there is no dirty-tree check. Resolve these paths,
|
|
42
|
+
all absolute: `GC` = `git rev-parse --git-common-dir` (resolve it to an absolute path), `WT` =
|
|
43
|
+
`GC/gbuild/<slug>` — the feature's worktree root, inside `.git/` so nothing under it is ever committed —
|
|
44
|
+
and `FT` = `WT/tree`, the feature worktree, the one place the feature branch is checked out. Then:
|
|
44
45
|
|
|
45
46
|
- `FT` is already a registered worktree (`git worktree list --porcelain`) → reuse it, say so.
|
|
46
47
|
- A branch named `<slug>` or ending `/<slug>` already exists → if it's checked out somewhere (a feature
|
|
@@ -55,14 +56,13 @@ both absolute: `GC` = `git rev-parse --git-common-dir` (resolve it to an absolut
|
|
|
55
56
|
Take `<prefix>` from the repo's convention — project or user instructions first, else the dominant
|
|
56
57
|
pattern in `git branch --list` — and fall back to `gbuild` when there is none.
|
|
57
58
|
|
|
58
|
-
Report the branch and `FT`. Everything below happens in `FT`; `DB` below is
|
|
59
|
-
`FT/.gbuild/<slug>/db`.
|
|
59
|
+
Report the branch and `FT`. Everything below happens in `FT`; `DB` below is `WT/db`.
|
|
60
60
|
|
|
61
61
|
### 2. Analyse the codebase
|
|
62
62
|
|
|
63
63
|
Read the project manifest(s), directory structure, `README.md`, and — for related in-flight work — the
|
|
64
|
-
`Feature` of every existing store (`feature.cypher` against each `GC/gbuild/*/
|
|
65
|
-
|
|
64
|
+
`Feature` of every existing store (`feature.cypher` with `--read-only` against each `GC/gbuild/*/db`,
|
|
65
|
+
one at a time). Resolve
|
|
66
66
|
file paths or URLs in `$ARGUMENTS`; if a reference fails to load, say so and ask.
|
|
67
67
|
|
|
68
68
|
### 3. Validate and explore
|
|
@@ -146,16 +146,16 @@ design, don't annotate around a failing item.
|
|
|
146
146
|
|
|
147
147
|
### 8. Create the store and write the graph
|
|
148
148
|
|
|
149
|
-
Create the store exactly as `reference/cypher.md` § Creating a store shows (`mkdir`,
|
|
150
|
-
`--snapshot-format json
|
|
149
|
+
Create the store exactly as `reference/cypher.md` § Creating a store shows (`mkdir -p DB`, then
|
|
150
|
+
`schema.cypher` with `--snapshot-format json`).
|
|
151
151
|
|
|
152
152
|
Then write the whole graph as **one** Cypher script, piped through a quoted heredoc.
|
|
153
153
|
`${CLAUDE_PLUGIN_ROOT}/templates/example.cypher` is a complete worked example — follow its structure:
|
|
154
154
|
`.begin`, a single statement of `CREATE` clauses (so variables like `a1` or `a_value` stay in scope for
|
|
155
|
-
the edges), `.commit
|
|
155
|
+
the edges), `.commit`.
|
|
156
156
|
|
|
157
157
|
```
|
|
158
|
-
cypherlite DB <<'CYPHER'
|
|
158
|
+
cypherlite query --database DB <<'CYPHER'
|
|
159
159
|
.begin
|
|
160
160
|
CREATE (f:Feature {feature: '<slug>', destination: '...', context: '...', out_of_scope: ['...']})
|
|
161
161
|
CREATE (a1:Acceptance {id: 'a-1', text: '...'})
|
|
@@ -168,7 +168,6 @@ CREATE (m)-[:DEPENDS_ON]->(n)
|
|
|
168
168
|
CREATE (m)-[:INPUT]->(:Field {name: '...', shape: '<...>'})-[:FROM]->(n_out)
|
|
169
169
|
CREATE (m)-[:SATISFIES]->(a1);
|
|
170
170
|
.commit
|
|
171
|
-
.checkpoint
|
|
172
171
|
CYPHER
|
|
173
172
|
```
|
|
174
173
|
|
|
@@ -178,30 +177,26 @@ slug) fails the transaction and writes nothing — fix the script and run it aga
|
|
|
178
177
|
### 9. Validate
|
|
179
178
|
|
|
180
179
|
```
|
|
181
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/validate.cypher
|
|
180
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/validate.cypher
|
|
182
181
|
```
|
|
183
182
|
|
|
184
183
|
No output means valid. Every row is a violation (`check`, `detail`): fix it with Cypher — a `.begin` …
|
|
185
|
-
`.commit`
|
|
186
|
-
hand off
|
|
184
|
+
`.commit` script of `MATCH … SET/CREATE/DELETE` — and re-run until it prints nothing. Never
|
|
185
|
+
hand off a graph that fails validation, and never edit `graph.json` directly.
|
|
187
186
|
|
|
188
187
|
Then confirm run-readiness:
|
|
189
188
|
|
|
190
189
|
```
|
|
191
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
|
|
190
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
|
|
192
191
|
```
|
|
193
192
|
|
|
194
193
|
One row per wave: each row's `open` slugs are the decomposition, and the `frontier` counts are what
|
|
195
194
|
`run` claims first. Nodes you expected to run together should share a wave.
|
|
196
195
|
|
|
197
|
-
### 10.
|
|
196
|
+
### 10. Report and stop
|
|
198
197
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
`db/graph.json` and `db/.gitignore`. Stage and commit from the feature worktree:
|
|
202
|
-
`git -C FT add .gbuild/<slug>` and `git -C FT commit -m "<slug>: chart graph"`.
|
|
203
|
-
|
|
204
|
-
Report the branch, `FT`, the waves, and the frontier. Close with `next: /gbuild:run <slug>`.
|
|
198
|
+
There is nothing to commit — the store is machine-local, outside every checkout. Report the branch,
|
|
199
|
+
`FT`, the waves, and the frontier. Close with `next: /gbuild:run <slug>`.
|
|
205
200
|
|
|
206
201
|
## Reopen
|
|
207
202
|
|
|
@@ -220,7 +215,7 @@ Report the branch, `FT`, the waves, and the frontier. Close with `next: /gbuild:
|
|
|
220
215
|
3. Write it as one script that `MATCH`es what it connects to and `CREATE`s the rest:
|
|
221
216
|
|
|
222
217
|
```
|
|
223
|
-
cypherlite DB <<'CYPHER'
|
|
218
|
+
cypherlite query --database DB <<'CYPHER'
|
|
224
219
|
.begin
|
|
225
220
|
MATCH (f:Feature), (up:GbuildNode {slug: '<existing-slug>'})-[:OUTPUT]->(up_out:Field {name: '<field>'})
|
|
226
221
|
CREATE (f)-[:HAS_ACCEPTANCE]->(a:Acceptance {id: 'a-3', text: '...'})
|
|
@@ -230,13 +225,11 @@ Report the branch, `FT`, the waves, and the frontier. Close with `next: /gbuild:
|
|
|
230
225
|
CREATE (n)-[:OUTPUT]->(:Field {name: '...', shape: '<...>'})
|
|
231
226
|
CREATE (n)-[:SATISFIES]->(a);
|
|
232
227
|
.commit
|
|
233
|
-
.checkpoint
|
|
234
228
|
CYPHER
|
|
235
229
|
```
|
|
236
230
|
|
|
237
|
-
4. **Re-run `validate.cypher`** until it prints nothing, then `progress.cypher
|
|
238
|
-
|
|
239
|
-
same ignore rule as Chart's step 10), report the new frontier.
|
|
231
|
+
4. **Re-run `validate.cypher`** until it prints nothing, then `progress.cypher`, and report the new
|
|
232
|
+
frontier.
|
|
240
233
|
|
|
241
234
|
If the requirement needs no new nodes (an existing node's contract already covers it), say so and stop
|
|
242
235
|
— don't manufacture graph churn.
|
package/skills/pr/SKILL.md
CHANGED
|
@@ -12,9 +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 — if exactly one feature worktree exists (`<git-common-dir>/gbuild/*/tree`), that's the slug; otherwise fall back to the most recently modified `graph.json` under `<git-common-dir>/gbuild/*/
|
|
15
|
+
- **slug**: the first token that isn't a flag. If absent, infer it — if exactly one feature worktree exists (`<git-common-dir>/gbuild/*/tree`), that's the slug; otherwise fall back to the most recently modified `graph.json` under `<git-common-dir>/gbuild/*/db`. If neither resolves, leave `<slug>` unresolved (the auto-fix step degrades gracefully — see Step 4).
|
|
16
16
|
|
|
17
|
-
When `<slug>` resolved, every graph read below goes through `cypherlite`: run `cypherlite --version` first (missing → stop; gbuild needs it), one command at a time, always `--mode jsonl` (no output = no rows), and on `storage locked` wait and retry up to 3 times. Anything else: `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md`. `DB` below is
|
|
17
|
+
When `<slug>` resolved, every graph read below goes through `cypherlite`: run `cypherlite --version` first (missing → stop; gbuild needs it), one command at a time, always `--read-only --mode jsonl` (no output = no rows — this skill only reads the store), and on `storage locked` wait and retry up to 3 times. Anything else: `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md`. `DB` below is `<git-common-dir>/gbuild/<slug>/db`, beside the feature worktree (a gbuild ≤ 0.7.1 store needs the move in `reference/cypher.md`).
|
|
18
18
|
- **max_rounds**: the value of `--max-rounds N` (also accept `--max-rounds=N`). Default `3` when absent.
|
|
19
19
|
|
|
20
20
|
## Step 1: Preconditions
|
|
@@ -27,7 +27,7 @@ Verify the environment before touching the remote. Stop with a clear, actionable
|
|
|
27
27
|
4. **Feature worktree and branch.** Resolve `FT` (the feature worktree) and `<branch>` (the feature branch checked out there) exactly as `/gbuild:run`'s step 0 describes — the registered worktree at `<git-common-dir>/gbuild/<slug>/tree`, a legacy feature whose branch is in the main tree, or attach a branch that is checked out nowhere. When `<slug>` is unresolved, use the main tree's current branch as `<branch>` and its root as `FT`. If `<branch>` equals `<base>`, stop — there is nothing to open a PR for.
|
|
28
28
|
5. **Clean tree.** Check for uncommitted changes in the feature worktree (`git -C FT status --porcelain`). `/gbuild:run` commits each node's work as it goes, so it should be clean. If there are uncommitted changes, warn the user and ask whether to proceed (they may want to commit first).
|
|
29
29
|
6. **Commits ahead of base.** Confirm the branch has commits the base lacks (`git log <base>..<branch> --oneline`). If empty, stop — nothing to push.
|
|
30
|
-
7. **Graph finished.** When `<slug>` resolved, run `cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher`. If any row's `open` is non-empty, warn that the graph isn't finished (name the open nodes) and ask whether to open the PR anyway. If any row has `failed` > 0, get their names from `attention.cypher` and name them — a PR built on an escalated node is usually premature.
|
|
30
|
+
7. **Graph finished.** When `<slug>` resolved, run `cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher`. If any row's `open` is non-empty, warn that the graph isn't finished (name the open nodes) and ask whether to open the PR anyway. If any row has `failed` > 0, get their names from `attention.cypher` and name them — a PR built on an escalated node is usually premature.
|
|
31
31
|
|
|
32
32
|
## Step 2: Determine the remote & push
|
|
33
33
|
|
|
@@ -48,7 +48,7 @@ Gather context from:
|
|
|
48
48
|
|
|
49
49
|
- Commit subjects: `git log <base>..<branch> --oneline`.
|
|
50
50
|
- File overview: `git diff <base>...<branch> --stat`.
|
|
51
|
-
- When `<slug>` resolved: `cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/feature.cypher` — the `destination` and the acceptance bar (with the nodes covering each criterion).
|
|
51
|
+
- When `<slug>` resolved: `cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/feature.cypher` — the `destination` and the acceptance bar (with the nodes covering each criterion).
|
|
52
52
|
|
|
53
53
|
Derive a concise, conventional-commit-style title from the feature/branch and the changes (e.g. `feat(auth): add OAuth login`).
|
|
54
54
|
|
|
@@ -103,4 +103,6 @@ next: /gbuild:status <slug>
|
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
The feature worktree `FT` keeps the branch checked out until removed — once the PR is merged and the
|
|
106
|
-
graph is no longer needed, `git worktree remove
|
|
106
|
+
graph is no longer needed, `git worktree remove WT/tree && rm -rf WT && git branch -d <branch>` (with
|
|
107
|
+
`WT` = `<git-common-dir>/gbuild/<slug>`) cleans up: the whole `WT`, store included, dies with the
|
|
108
|
+
feature.
|
package/skills/review/SKILL.md
CHANGED
|
@@ -12,21 +12,22 @@ missed abstractions that only exist *between* nodes, which no per-node review ca
|
|
|
12
12
|
|
|
13
13
|
`$ARGUMENTS` is optional. If present, treat it as the feature slug. If absent, infer it — if exactly one
|
|
14
14
|
feature worktree exists (`<git-common-dir>/gbuild/*/tree`), that's the slug; otherwise fall back to the
|
|
15
|
-
most recently modified `graph.json` under `<git-common-dir>/gbuild/*/
|
|
16
|
-
features charted before the worktree layout, `.gbuild/*/db/graph.json` in the main tree). Do NOT write
|
|
15
|
+
most recently modified `graph.json` under `<git-common-dir>/gbuild/*/db`. Do NOT write
|
|
17
16
|
any file — this skill outputs to chat exclusively.
|
|
18
17
|
|
|
19
18
|
Resolve `FT`, the feature worktree, exactly as `/gbuild:run`'s step 0 describes (reuse the registered
|
|
20
|
-
worktree, attach if the feature branch is checked out nowhere). `DB` below is
|
|
19
|
+
worktree, attach if the feature branch is checked out nowhere). `DB` below is
|
|
20
|
+
`<git-common-dir>/gbuild/<slug>/db`, beside the worktree (a gbuild ≤ 0.7.1 store needs the move in
|
|
21
|
+
`reference/cypher.md`).
|
|
21
22
|
|
|
22
23
|
Store rules: run `cypherlite --version` first (missing → stop; gbuild needs it). One `cypherlite`
|
|
23
|
-
command at a time, always `--mode jsonl` (no output = no rows
|
|
24
|
-
3 times. Anything else: `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md`.
|
|
24
|
+
command at a time, always `--read-only --mode jsonl` (no output = no rows — this skill only reads); on
|
|
25
|
+
`storage locked` wait and retry up to 3 times. Anything else: `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md`.
|
|
25
26
|
|
|
26
27
|
Check the graph is finished — one row per wave, cheap:
|
|
27
28
|
|
|
28
29
|
```
|
|
29
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
|
|
30
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
|
|
30
31
|
```
|
|
31
32
|
|
|
32
33
|
If any row's `open` is non-empty, say the graph isn't finished (name the open nodes) and ask whether to
|
|
@@ -38,7 +39,7 @@ address.
|
|
|
38
39
|
Fetch the feature context:
|
|
39
40
|
|
|
40
41
|
```
|
|
41
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/feature.cypher
|
|
42
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/feature.cypher
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
Launch the `gbuild-auditor` subagent (agents/gbuild-auditor.md — this plugin's own copy, gbuild does not
|
package/skills/run/SKILL.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
description: Executes a gbuild graph — dispatches every ready-and-independent node in the current wave concurrently, each file-touching node in its own git worktree, reviews each node's output with gbuild-reviewer before merging its branch and 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 the graph for the feature `$ARGUMENTS` (the slug; step 0 resolves `DB`, the store —
|
|
6
|
-
|
|
5
|
+
Run the graph for the feature `$ARGUMENTS` (the slug; step 0 resolves `DB`, the store — the feature
|
|
6
|
+
branch lives in its own worktree, so this skill never changes the branch of the user's checkout).
|
|
7
7
|
|
|
8
8
|
**CRITICAL: this skill must run in the main context, not inside a forked agent.** It dispatches its own
|
|
9
9
|
subagents per node; a subagent cannot itself fan out further subagents reliably. It is also the store's
|
|
@@ -17,6 +17,8 @@ back in their final message, and this skill records it.
|
|
|
17
17
|
- One `cypherlite` command at a time against `DB` — never parallel tool calls on it, never from a subagent.
|
|
18
18
|
- Always `--mode jsonl`: one JSON object per row, no output = no rows. Every `--param` value is JSON,
|
|
19
19
|
single-quoted for the shell (`--param 'slugs=["a","b"]'`).
|
|
20
|
+
- Pure reads (validate, attention, progress below) open the store `--read-only`; the writes (dispatch,
|
|
21
|
+
set-status, record) stay writable — the CLI checkpoints a writable store on exit itself.
|
|
20
22
|
- `storage locked` → another process holds the store: wait a few seconds, retry up to 3 times, then stop.
|
|
21
23
|
Exit code 1 = failure; read stderr. Anything beyond the scripts below: `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md`.
|
|
22
24
|
- Never re-read what you already hold. The claimed wave's definitions stay valid for its retries.
|
|
@@ -28,7 +30,7 @@ Default to `git`. Resolve these facts first, absolute paths, and reuse them thro
|
|
|
28
30
|
- `GC` = `git rev-parse --git-common-dir`, resolved to an absolute path; `WT` = `GC/gbuild/$ARGUMENTS`
|
|
29
31
|
(the worktree root — inside `.git/`, so worktrees never appear in `git status` or get committed).
|
|
30
32
|
- `FT` = the feature worktree and `BRANCH` = the feature branch — the one place `BRANCH` is checked
|
|
31
|
-
out, and where every merge
|
|
33
|
+
out, and where every merge below lands:
|
|
32
34
|
1. `WT/tree` is a registered worktree (`git worktree list --porcelain`) → `FT` = it, `BRANCH` =
|
|
33
35
|
`git -C FT branch --show-current`.
|
|
34
36
|
2. Else a worktree whose branch is `$ARGUMENTS` or ends `/$ARGUMENTS` → `FT` = that worktree's path
|
|
@@ -36,14 +38,14 @@ Default to `git`. Resolve these facts first, absolute paths, and reuse them thro
|
|
|
36
38
|
3. Else such a branch exists but is checked out nowhere → attach it: `git worktree add WT/tree
|
|
37
39
|
<branch>`, `FT` = `WT/tree`.
|
|
38
40
|
4. Else → stop: there is no feature branch for `$ARGUMENTS` — chart it with `/gbuild:plan` first.
|
|
39
|
-
- `DB` = `
|
|
40
|
-
the
|
|
41
|
+
- `DB` = `WT/db` — the feature's store, beside the worktree: machine-local, never committed (a gbuild ≤ 0.7.1
|
|
42
|
+
store needs the move in `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md`).
|
|
41
43
|
|
|
42
44
|
Then check and recover:
|
|
43
45
|
|
|
44
46
|
```
|
|
45
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/validate.cypher
|
|
46
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/attention.cypher
|
|
47
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/validate.cypher
|
|
48
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/attention.cypher
|
|
47
49
|
```
|
|
48
50
|
|
|
49
51
|
- `validate` printing anything → stop and report the rows; do not run a graph `plan` didn't finish
|
|
@@ -55,7 +57,7 @@ cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/attention.cypher
|
|
|
55
57
|
them all in one call so they re-dispatch, and mention it in the report:
|
|
56
58
|
|
|
57
59
|
```
|
|
58
|
-
cypherlite DB --mode jsonl --param 'slugs=["<slug>", ...]' --param 'status="pending"' \
|
|
60
|
+
cypherlite query --database DB --mode jsonl --param 'slugs=["<slug>", ...]' --param 'status="pending"' \
|
|
59
61
|
< ${CLAUDE_PLUGIN_ROOT}/cypher/set-status.cypher
|
|
60
62
|
```
|
|
61
63
|
|
|
@@ -87,7 +89,7 @@ behavior this plugin replaces.
|
|
|
87
89
|
1. **CLAIM.**
|
|
88
90
|
|
|
89
91
|
```
|
|
90
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/dispatch.cypher
|
|
92
|
+
cypherlite query --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/dispatch.cypher
|
|
91
93
|
```
|
|
92
94
|
|
|
93
95
|
It moves the whole frontier to `in_progress` and prints one row per claimed node with everything its
|
|
@@ -122,7 +124,7 @@ behavior this plugin replaces.
|
|
|
122
124
|
nested into a string;
|
|
123
125
|
- record its own UTC start and finish (`date -u +%Y-%m-%dT%H:%M:%SZ`) and end its final message with
|
|
124
126
|
`{"started_at": "...", "completed_at": "...", "outputs": {...}}`;
|
|
125
|
-
- **not** run `cypherlite` or touch
|
|
127
|
+
- **not** run `cypherlite` or touch the store.
|
|
126
128
|
|
|
127
129
|
3. **REVIEW.** Once IMPLEMENT returns, spawn a `gbuild-reviewer` per node, again all in one message
|
|
128
130
|
(`agents/gbuild-reviewer.md` — this plugin's own copy, gbuild does not depend on hone-ai being
|
|
@@ -151,7 +153,7 @@ behavior this plugin replaces.
|
|
|
151
153
|
`VERDICT:` line, `failed_criteria` from its `[fail]` lines:
|
|
152
154
|
|
|
153
155
|
```
|
|
154
|
-
cypherlite DB --mode jsonl --param 'results=[
|
|
156
|
+
cypherlite query --database DB --mode jsonl --param 'results=[
|
|
155
157
|
{"slug": "<slug>", "verdict": "pass", "failed_criteria": [], "outputs": {...},
|
|
156
158
|
"started_at": "<iso>", "completed_at": "<iso>"},
|
|
157
159
|
{"slug": "<slug>", "verdict": "fail", "failed_criteria": ["<criterion>"]}
|
|
@@ -186,15 +188,13 @@ user) changing branches in their own checkouts cannot race them.
|
|
|
186
188
|
|
|
187
189
|
## Step 3: Next wave
|
|
188
190
|
|
|
189
|
-
|
|
190
|
-
.gbuild/<feature>/db` and `git -C FT commit -m "<feature>: record wave <n>"`. Then claim again (step 2).
|
|
191
|
-
Keep going until a claim returns no rows.
|
|
191
|
+
Claim again (step 2). Keep going until a claim returns no rows.
|
|
192
192
|
|
|
193
193
|
## Step 4: Report and stop
|
|
194
194
|
|
|
195
195
|
```
|
|
196
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
|
|
197
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/attention.cypher
|
|
196
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
|
|
197
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/attention.cypher
|
|
198
198
|
```
|
|
199
199
|
|
|
200
200
|
Every `progress` row with `open: []` → the graph is done. Otherwise `attention` names what's stuck
|
package/skills/status/SKILL.md
CHANGED
|
@@ -3,16 +3,17 @@ description: Reports a gbuild feature's graph — frontier, blocked, in-flight,
|
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
Report status for `$ARGUMENTS`. This skill only reads the store. `DB` below is the feature's store:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
is gone
|
|
6
|
+
`<git-common-dir>/gbuild/<feature>/db`, beside the feature worktree `FT` at
|
|
7
|
+
`<git-common-dir>/gbuild/<feature>/tree` — machine-local, never committed (a gbuild ≤ 0.7.1 store needs the
|
|
8
|
+
move in `reference/cypher.md`). Status never creates or attaches worktrees — if the store is missing,
|
|
9
|
+
the feature is gone (or was never charted here); say so.
|
|
10
10
|
|
|
11
11
|
## Store rules
|
|
12
12
|
|
|
13
13
|
- `cypherlite --version` first. If it's missing, stop: gbuild needs it
|
|
14
14
|
(`curl -sSfL https://neo4j-labs.github.io/cypherlite/install.sh | bash`).
|
|
15
15
|
- One `cypherlite` command at a time — never parallel tool calls on the same store.
|
|
16
|
+
- Always `--read-only`: status never writes, and a missing store fails fast instead of being created.
|
|
16
17
|
- Always `--mode jsonl`: one JSON object per row, no output = no rows.
|
|
17
18
|
- `storage locked` → another process (likely a running `/gbuild:run`) holds the store: wait a few
|
|
18
19
|
seconds, retry up to 3 times, then say so. Anything else: `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md`.
|
|
@@ -31,8 +32,8 @@ This is the human-facing report, so it's the one place that reads every node.
|
|
|
31
32
|
### 1. Load
|
|
32
33
|
|
|
33
34
|
```
|
|
34
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/status.cypher
|
|
35
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/validate.cypher
|
|
35
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/status.cypher
|
|
36
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/validate.cypher
|
|
36
37
|
```
|
|
37
38
|
|
|
38
39
|
One call after the other. `status.cypher` gives one row per node with its derived `state`
|
|
@@ -80,11 +81,11 @@ don't let silence be ambiguous between "checked, clear" and "not checked."
|
|
|
80
81
|
|
|
81
82
|
## All-features mode
|
|
82
83
|
|
|
83
|
-
Don't read every node of every feature. For each store found — `<git-common-dir>/gbuild/*/
|
|
84
|
-
|
|
84
|
+
Don't read every node of every feature. For each store found — `<git-common-dir>/gbuild/*/db` — one
|
|
85
|
+
store at a time:
|
|
85
86
|
|
|
86
87
|
```
|
|
87
|
-
cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
|
|
88
|
+
cypherlite query --read-only --database DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
|
|
88
89
|
```
|
|
89
90
|
|
|
90
91
|
Print one line per feature: slug, node counts by state summed over its waves, and whether it's done
|
package/templates/example.cypher
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// A worked 4-node diamond: A produces a value, B and C each consume it
|
|
2
2
|
// independently, D joins both. This is exactly the script plan writes for a
|
|
3
3
|
// new feature — one atomic statement, piped into the store:
|
|
4
|
-
// cypherlite
|
|
4
|
+
// cypherlite query --database <git-common-dir>/gbuild/<slug>/db < plan.cypher
|
|
5
5
|
// Variables (f, a1, a, a_value, ...) are only scoped to this one statement, so
|
|
6
6
|
// the whole graph is created in a single CREATE chain.
|
|
7
7
|
.begin
|
|
@@ -54,4 +54,3 @@ CREATE (d)-[:INPUT]->(:Field {name: 'squared', shape: '<integer>'})-[:FROM]->(c_
|
|
|
54
54
|
CREATE (d)-[:OUTPUT]->(:Field {name: 'sum', shape: '<integer>'})
|
|
55
55
|
CREATE (d)-[:SATISFIES]->(a2);
|
|
56
56
|
.commit
|
|
57
|
-
.checkpoint
|