buildwright 0.0.14 → 0.0.16

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 CHANGED
@@ -95,6 +95,12 @@ and Buildwright-owned support scripts. It also removes paths from the old
95
95
  pre-`/bw-work` model so generated tool configs do not contain both old and new
96
96
  workflows.
97
97
 
98
+ Steering is only touched if Buildwright ships the file. The default
99
+ `philosophy.md` is refreshed in place only when it is unmodified (a known shipped
100
+ version); a customized `philosophy.md` is preserved. Any steering file Buildwright
101
+ does not ship — your `tech.md`, `product.md`, or org-injected docs such as
102
+ `quality-gates.md` — is never deleted or overwritten.
103
+
98
104
  ### From Source
99
105
 
100
106
  ```bash
@@ -103,6 +109,49 @@ cd buildwright
103
109
  make sync
104
110
  ```
105
111
 
112
+ ### Global install
113
+
114
+ Per-project `buildwright init` is the recommended setup — it commits the
115
+ workflow config to your repo so it is versioned and shared with your team. If
116
+ you would rather have the workflow available in **every** project without
117
+ running `init` each time, install it globally from a Buildwright checkout.
118
+
119
+ ```bash
120
+ make global # install for all supported tools at once
121
+ ```
122
+
123
+ Or install for a single tool:
124
+
125
+ | Command | Tool | Installs to |
126
+ |---------|------|-------------|
127
+ | `make claude` | Claude Code | `~/.claude/commands/`, `~/.claude/agents/` |
128
+ | `make codex` | Codex CLI | `~/.agents/skills/buildwright/` (symlink) |
129
+ | `make opencode` | OpenCode | `~/.config/opencode/skills/buildwright/` |
130
+ | `make openclaw` | OpenClaw | `~/.openclaw/skills/buildwright/` |
131
+
132
+ Global install makes the **workflow** (the `/bw-*` commands and agents)
133
+ discoverable everywhere. Project-specific context — steering docs, tech/product
134
+ details, and `/bw-analyse` codebase docs — still comes from each project's
135
+ `.buildwright/` directory. In a project without `.buildwright/`, commands fall
136
+ back to stack auto-detection, and the `/bw-work` and `/bw-ship` review steps read
137
+ the engineer personas from `~/.claude/agents/` (installed by `make claude`). Run
138
+ `buildwright init` there when you want full project context (custom steering,
139
+ codebase docs).
140
+
141
+ Note: `make claude` is what installs the `security-engineer` / `staff-engineer`
142
+ persona files into `~/.claude/agents/`, so Claude Code's review steps find them
143
+ everywhere. The other tools install commands/skills only — under
144
+ Codex/OpenCode/OpenClaw the review personas come from a project's
145
+ `.buildwright/agents/`, so run `buildwright init` for full reviews there.
146
+
147
+ Re-run the same command after `git pull` to update. To uninstall:
148
+
149
+ ```bash
150
+ rm ~/.claude/commands/bw-*.md ~/.claude/agents/{staff,security}-engineer.md
151
+ rm ~/.agents/skills/buildwright # codex symlink
152
+ rm -rf ~/.config/opencode/skills/buildwright ~/.openclaw/skills/buildwright
153
+ ```
154
+
106
155
  ## Project Layout
107
156
 
108
157
  ```text
@@ -119,14 +168,16 @@ make sync
119
168
  steering/
120
169
  philosophy.md
121
170
 
171
+ AGENTS.md # canonical agent instructions (committed)
172
+ CLAUDE.md # pointer stub → AGENTS.md (committed)
122
173
  .claude/ # generated by make sync
123
174
  .opencode/ # generated by make sync
124
175
  .cursor/rules/ # generated by make sync
125
- AGENTS.md # generated by make sync
126
176
  skills/ # generated by make sync for Codex CLI
127
177
  ```
128
178
 
129
- `.buildwright/` is canonical. Generated tool directories are gitignored.
179
+ `.buildwright/` and `AGENTS.md` are canonical and committed. `CLAUDE.md` is a
180
+ pointer stub to `AGENTS.md`. Generated tool directories are gitignored.
130
181
 
131
182
  ## Development
132
183
 
@@ -138,8 +189,8 @@ make sync-check
138
189
  make validate
139
190
  ```
140
191
 
141
- `make sync` regenerates tool-specific config, Codex skills, `AGENTS.md`, and the
142
- CLI README.
192
+ `make sync` regenerates tool-specific config, Codex skills, and the CLI README.
193
+ `AGENTS.md` and `CLAUDE.md` are hand-maintained root files, not generated.
143
194
 
144
195
  ## Configuration
145
196
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "buildwright",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "description": "Lightweight engineering workflow for agent-led development.",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -15,6 +15,7 @@
15
15
  "templates/"
16
16
  ],
17
17
  "scripts": {
18
+ "test": "node --test",
18
19
  "prepack": "node scripts/prepack.js",
19
20
  "postpack": "node scripts/postpack.js"
20
21
  },
@@ -2,6 +2,7 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
+ const crypto = require('crypto');
5
6
  const https = require('https');
6
7
  const { execSync } = require('child_process');
7
8
  const { isBuildwrightInstalled } = require('../utils/detect');
@@ -35,9 +36,6 @@ const REMOVED_PATHS = [
35
36
  '.buildwright/claws',
36
37
  '.buildwright/skills',
37
38
  '.buildwright/tasks/TEMPLATE.md',
38
- '.buildwright/steering/quality-gates.md',
39
- '.buildwright/steering/naming-conventions.md',
40
- '.buildwright/steering/engineering-philosophy.md',
41
39
  'docs/requirements/TEMPLATE.md',
42
40
  '.claude/commands/bw-new-feature.md',
43
41
  '.claude/commands/bw-quick.md',
@@ -65,6 +63,60 @@ const REMOVED_PATHS = [
65
63
  'skills/bw-help',
66
64
  ];
67
65
 
66
+ // Steering files Buildwright ships and may update in place. Keyed by filename,
67
+ // each value is the set of SHA-256 hashes of every version Buildwright has ever
68
+ // shipped for that file. An existing steering file is overwritten on update ONLY
69
+ // when its hash is in this set (i.e. it is an unmodified, previously-shipped
70
+ // copy); a customized file (hash absent) is preserved. Files Buildwright does not
71
+ // ship at all are never touched.
72
+ //
73
+ // RELEASE STEP: whenever a managed steering file changes, append the superseded
74
+ // version's SHA-256 here so unmodified installs keep auto-updating.
75
+ const MANAGED_STEERING_HASHES = {
76
+ 'philosophy.md': new Set([
77
+ '476fe491e139a211d9483942bd60435513813227c589ae0c29ba1e082672757a',
78
+ ]),
79
+ };
80
+
81
+ function sha256(filePath) {
82
+ return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
83
+ }
84
+
85
+ /**
86
+ * Copy shipped steering files into dest. New shipped files are added. An existing
87
+ * file is overwritten only when its content matches a known shipped hash (i.e. the
88
+ * user has not customized it); customized or unmanaged files are preserved. Files
89
+ * not shipped by Buildwright are never touched. Steering is a flat dir of .md files.
90
+ * @param {object} [managedHashes] - filename -> Set of known shipped hashes
91
+ * @returns {{updated: string[], preserved: string[]}}
92
+ */
93
+ function updateSteering(src, dest, managedHashes = MANAGED_STEERING_HASHES) {
94
+ fs.mkdirSync(dest, { recursive: true });
95
+ const updated = [];
96
+ const preserved = [];
97
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
98
+ if (!entry.isFile()) continue;
99
+ const realSrc = fs.realpathSync(path.join(src, entry.name));
100
+ const destPath = path.join(dest, entry.name);
101
+ if (!fs.existsSync(destPath)) {
102
+ fs.copyFileSync(realSrc, destPath);
103
+ updated.push(entry.name);
104
+ continue;
105
+ }
106
+ const known = managedHashes[entry.name];
107
+ const localHash = sha256(destPath);
108
+ if (known && known.has(localHash)) {
109
+ if (sha256(realSrc) !== localHash) {
110
+ fs.copyFileSync(realSrc, destPath);
111
+ updated.push(entry.name);
112
+ }
113
+ } else {
114
+ preserved.push(entry.name);
115
+ }
116
+ }
117
+ return { updated, preserved };
118
+ }
119
+
68
120
  /**
69
121
  * Download a URL following redirects. Returns a Buffer.
70
122
  */
@@ -120,7 +172,7 @@ async function update() {
120
172
 
121
173
  console.log(`${BOLD}Updating Buildwright in ${cwd}...${RESET}\n`);
122
174
  console.log(`Updating: ${UPDATE_DIRS.map(d => `.buildwright/${d}/`).join(', ')}`);
123
- console.log(`Preserving: project-created steering files such as tech.md and product.md\n`);
175
+ console.log(`Preserving: customized and org-injected steering files (only an unmodified philosophy.md is refreshed)\n`);
124
176
 
125
177
  let tmpDir;
126
178
  try {
@@ -163,7 +215,14 @@ async function update() {
163
215
  }
164
216
  console.log(` Updating .buildwright/${dir}/`);
165
217
  fs.mkdirSync(dest, { recursive: true });
166
- copyDir(src, dest, { skipExisting: dir === 'steering' });
218
+ if (dir === 'steering') {
219
+ const { preserved } = updateSteering(src, dest);
220
+ if (preserved.length > 0) {
221
+ console.log(` Preserved customized steering files: ${preserved.join(', ')}`);
222
+ }
223
+ } else {
224
+ copyDir(src, dest);
225
+ }
167
226
  }
168
227
 
169
228
  for (const file of SUPPORT_FILES) {
@@ -175,12 +234,15 @@ async function update() {
175
234
  }
176
235
  console.log(` Updated Buildwright support scripts`);
177
236
 
178
- // Also add CLAUDE.md if it doesn't already exist locally
179
- const srcClaude = path.join(extractedRoot, 'CLAUDE.md');
180
- const destClaude = path.join(cwd, 'CLAUDE.md');
181
- if (fs.existsSync(srcClaude) && !fs.existsSync(destClaude)) {
182
- console.log(` Adding CLAUDE.md`);
183
- fs.copyFileSync(srcClaude, destClaude);
237
+ // Add the canonical AGENTS.md and the CLAUDE.md pointer stub if absent
238
+ // locally. Existing files are left untouched (treated as user-owned).
239
+ for (const file of ['AGENTS.md', 'CLAUDE.md']) {
240
+ const src = path.join(extractedRoot, file);
241
+ const dest = path.join(cwd, file);
242
+ if (fs.existsSync(src) && !fs.existsSync(dest)) {
243
+ console.log(` Adding ${file}`);
244
+ fs.copyFileSync(src, dest);
245
+ }
184
246
  }
185
247
 
186
248
  console.log('');
@@ -208,4 +270,4 @@ async function update() {
208
270
  }
209
271
  }
210
272
 
211
- module.exports = { update };
273
+ module.exports = { update, updateSteering, REMOVED_PATHS, MANAGED_STEERING_HASHES };
@@ -0,0 +1,86 @@
1
+ 'use strict';
2
+
3
+ const test = require('node:test');
4
+ const assert = require('node:assert');
5
+ const fs = require('fs');
6
+ const os = require('os');
7
+ const path = require('path');
8
+ const crypto = require('crypto');
9
+
10
+ const { updateSteering, REMOVED_PATHS, MANAGED_STEERING_HASHES } = require('./update');
11
+
12
+ const sha256 = (s) => crypto.createHash('sha256').update(s).digest('hex');
13
+
14
+ function tmpProject() {
15
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'bw-update-test-'));
16
+ const src = path.join(root, 'src');
17
+ const dest = path.join(root, 'dest');
18
+ fs.mkdirSync(src, { recursive: true });
19
+ fs.mkdirSync(dest, { recursive: true });
20
+ return { root, src, dest };
21
+ }
22
+
23
+ test('copies a shipped steering file that is absent locally', () => {
24
+ const { src, dest } = tmpProject();
25
+ fs.writeFileSync(path.join(src, 'philosophy.md'), 'NEW philosophy');
26
+
27
+ const { updated, preserved } = updateSteering(src, dest, {});
28
+
29
+ assert.deepStrictEqual(updated, ['philosophy.md']);
30
+ assert.deepStrictEqual(preserved, []);
31
+ assert.strictEqual(fs.readFileSync(path.join(dest, 'philosophy.md'), 'utf8'), 'NEW philosophy');
32
+ });
33
+
34
+ test('overwrites an unmodified shipped file (hash match) with the latest', () => {
35
+ const { src, dest } = tmpProject();
36
+ const oldContent = 'OLD philosophy';
37
+ fs.writeFileSync(path.join(dest, 'philosophy.md'), oldContent);
38
+ fs.writeFileSync(path.join(src, 'philosophy.md'), 'NEW philosophy');
39
+
40
+ const managed = { 'philosophy.md': new Set([sha256(oldContent)]) };
41
+ const { updated, preserved } = updateSteering(src, dest, managed);
42
+
43
+ assert.deepStrictEqual(updated, ['philosophy.md']);
44
+ assert.deepStrictEqual(preserved, []);
45
+ assert.strictEqual(fs.readFileSync(path.join(dest, 'philosophy.md'), 'utf8'), 'NEW philosophy');
46
+ });
47
+
48
+ test('preserves a customized steering file (hash not in the managed set)', () => {
49
+ const { src, dest } = tmpProject();
50
+ const customContent = 'CUSTOM org philosophy';
51
+ fs.writeFileSync(path.join(dest, 'philosophy.md'), customContent);
52
+ fs.writeFileSync(path.join(src, 'philosophy.md'), 'NEW philosophy');
53
+
54
+ // managed set only knows some other (shipped) hash, not the custom content
55
+ const managed = { 'philosophy.md': new Set([sha256('some shipped version')]) };
56
+ const { updated, preserved } = updateSteering(src, dest, managed);
57
+
58
+ assert.deepStrictEqual(updated, []);
59
+ assert.deepStrictEqual(preserved, ['philosophy.md']);
60
+ assert.strictEqual(fs.readFileSync(path.join(dest, 'philosophy.md'), 'utf8'), customContent);
61
+ });
62
+
63
+ test('never touches an org steering file that Buildwright does not ship', () => {
64
+ const { src, dest } = tmpProject();
65
+ // Buildwright ships only philosophy.md
66
+ fs.writeFileSync(path.join(src, 'philosophy.md'), 'NEW philosophy');
67
+ // org injected its own doc at a colliding-style path
68
+ const orgDoc = 'org quality gates';
69
+ fs.writeFileSync(path.join(dest, 'quality-gates.md'), orgDoc);
70
+
71
+ updateSteering(src, dest, MANAGED_STEERING_HASHES);
72
+
73
+ assert.strictEqual(fs.existsSync(path.join(dest, 'quality-gates.md')), true);
74
+ assert.strictEqual(fs.readFileSync(path.join(dest, 'quality-gates.md'), 'utf8'), orgDoc);
75
+ });
76
+
77
+ test('REMOVED_PATHS no longer deletes org-injected steering docs', () => {
78
+ assert.ok(!REMOVED_PATHS.includes('.buildwright/steering/quality-gates.md'));
79
+ assert.ok(!REMOVED_PATHS.includes('.buildwright/steering/naming-conventions.md'));
80
+ assert.ok(!REMOVED_PATHS.includes('.buildwright/steering/engineering-philosophy.md'));
81
+ });
82
+
83
+ test('REMOVED_PATHS still cleans up non-steering legacy paths', () => {
84
+ assert.ok(REMOVED_PATHS.includes('.buildwright/commands/bw-quick.md'));
85
+ assert.ok(REMOVED_PATHS.includes('.buildwright/agents/architect.md'));
86
+ });
@@ -1,9 +1,27 @@
1
1
  # Agent Personas
2
2
 
3
- This directory contains reusable review personas. They are prompt instructions,
4
- not separate runtimes.
3
+ This directory contains reusable review personas. Each file is a valid agent
4
+ definition (with `name`/`description` frontmatter) so the tools that expect a
5
+ subagent registry — Claude Code (`.claude/agents/`, `~/.claude/agents/`),
6
+ OpenCode (`.opencode/agents/`) — load them cleanly. They are still adopted
7
+ **inline** by the commands below, not spawned as separate orchestration runtimes;
8
+ Buildwright is not a multi-agent framework.
5
9
 
6
10
  | Agent | File | Used By | Purpose |
7
11
  |-------|------|---------|---------|
8
12
  | Staff Engineer | `staff-engineer.md` | `/bw-work`, `/bw-ship` | Spec and code review with confidence scoring and high-signal findings |
9
13
  | Security Engineer | `security-engineer.md` | `/bw-work`, `/bw-ship` | OWASP Top 10, secrets, auth, injection, dependency review |
14
+
15
+ ## How they are triggered
16
+
17
+ The reviews run automatically inside the command flows — there is no separate
18
+ step to invoke:
19
+
20
+ - `/bw-work` — Phase 7 (Security Review) and Phase 8 (Code Review) run after the
21
+ implementation passes its verification gates, before commit.
22
+ - `/bw-ship` — Step 2 (Security Review) and Step 3 (Code Review) run as part of
23
+ the ship pipeline, before push/PR.
24
+
25
+ At each of those phases the command adopts the matching persona — reading it from
26
+ the project's `.buildwright/agents/<name>.md`, or from `~/.claude/agents/<name>.md`
27
+ for a global install without a project `.buildwright/`.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: security-engineer
3
+ description: Security review persona — OWASP Top 10, secrets, authentication/authorization, injection, and dependency risks. Used by /bw-work and /bw-ship.
4
+ ---
5
+
1
6
  # Security Engineer Agent
2
7
 
3
8
  You are a **Security Engineer** specialized in application security with expertise in OWASP, secure coding, and vulnerability assessment.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: staff-engineer
3
+ description: Code and spec review persona — logic errors, edge cases, error handling, pattern fit, complexity, and missing tests/docs, with confidence scoring and high-signal findings. Used by /bw-work and /bw-ship.
4
+ ---
5
+
1
6
  # Staff Engineer Agent
2
7
 
3
8
  You are a **Staff Engineer** with 15+ years of experience building production systems at scale.
@@ -85,7 +85,9 @@ If FAIL after retries:
85
85
 
86
86
  ## Step 2: Security Review — No retry (needs human judgment)
87
87
 
88
- Adopt Security Engineer persona from `.buildwright/agents/security-engineer.md`.
88
+ Adopt the Security Engineer persona from `.buildwright/agents/security-engineer.md`.
89
+ For a global install in a project without `.buildwright/`, read it from
90
+ `~/.claude/agents/security-engineer.md` instead.
89
91
 
90
92
  ### 2.1 Determine Scope
91
93
  ```bash
@@ -142,7 +144,9 @@ If CRITICAL VULNERABILITIES:
142
144
 
143
145
  ## Step 3: Code Review — No retry (architectural decisions)
144
146
 
145
- Adopt Staff Engineer persona from `.buildwright/agents/staff-engineer.md`.
147
+ Adopt the Staff Engineer persona from `.buildwright/agents/staff-engineer.md`.
148
+ For a global install in a project without `.buildwright/`, read it from
149
+ `~/.claude/agents/staff-engineer.md` instead.
146
150
 
147
151
  ### 3.1 Determine Scope
148
152
  ```bash
@@ -112,7 +112,9 @@ gate fails, fix and retry up to `BUILDWRIGHT_AGENT_RETRIES` times, default 2.
112
112
 
113
113
  ## Phase 7: Security Review
114
114
 
115
- Adopt `.buildwright/agents/security-engineer.md`. Review the changed diff for:
115
+ Adopt the Security Engineer persona from `.buildwright/agents/security-engineer.md`
116
+ (or `~/.claude/agents/security-engineer.md` for a global install without a project
117
+ `.buildwright/`). Review the changed diff for:
116
118
  - Secrets
117
119
  - Dependency vulnerabilities, if tooling exists
118
120
  - Input validation and authorization
@@ -123,7 +125,9 @@ Stop on critical vulnerabilities.
123
125
 
124
126
  ## Phase 8: Code Review
125
127
 
126
- Adopt `.buildwright/agents/staff-engineer.md`. Review the changed diff for:
128
+ Adopt the Staff Engineer persona from `.buildwright/agents/staff-engineer.md`
129
+ (or `~/.claude/agents/staff-engineer.md` for a global install without a project
130
+ `.buildwright/`). Review the changed diff for:
127
131
  - Logic errors and missed edge cases
128
132
  - Error handling
129
133
  - Pattern fit and unnecessary complexity
@@ -0,0 +1,126 @@
1
+ # Buildwright Development
2
+
3
+ ## Mission
4
+
5
+ Agent-first disciplined development. Humans approve intent when needed; agents
6
+ understand, test, implement, document, verify, review, and ship.
7
+
8
+ ## Steering Documents
9
+
10
+ At the start of every session, recursively discover and read all `.md` files
11
+ under `.buildwright/steering/`. Use:
12
+
13
+ ```bash
14
+ find .buildwright/steering -type f -name "*.md" | sort
15
+ ```
16
+
17
+ The default steering file is `philosophy.md`.
18
+
19
+ Also recursively read all `.md` files under `.buildwright/codebase/` if that
20
+ directory exists. These are codebase analysis docs generated by `/bw-analyse`.
21
+
22
+ Do not assume a fixed set of project steering files. `tech.md` and `product.md`
23
+ are created only when Buildwright has real project-specific content.
24
+
25
+ ## Project Structure
26
+
27
+ `.buildwright/` and this `AGENTS.md` are the canonical, committed configuration.
28
+ Tool-specific directories are generated from `.buildwright/` by `make sync` and
29
+ gitignored:
30
+
31
+ ```
32
+ .buildwright/
33
+ agents/ # Staff Engineer, Security Engineer
34
+ codebase/ # Generated by /bw-analyse
35
+ commands/ # bw-work, bw-plan, bw-verify, bw-ship, bw-analyse
36
+ steering/ # philosophy.md plus lazy-created tech.md/product.md
37
+
38
+ AGENTS.md # Canonical agent instructions (this file)
39
+ CLAUDE.md # Pointer stub → AGENTS.md
40
+ .claude/ # Generated by make sync
41
+ .opencode/ # Generated by make sync
42
+ .cursor/rules/ # Generated by make sync
43
+ ```
44
+
45
+ After cloning or editing `.buildwright/`, run `make sync`.
46
+
47
+ ## Commands
48
+
49
+ Use the smallest command that matches the intent:
50
+
51
+ 1. `/bw-plan` — think/research only; no code changes, commits, or PRs.
52
+ 2. `/bw-work` — implement bug fixes, refactors, and features.
53
+ 3. `/bw-verify` — run typecheck, lint, test, and build gates.
54
+ 4. `/bw-ship` — verify, security review, code review, push, and PR.
55
+ 5. `/bw-analyse` — analyse brownfield codebases and write `.buildwright/codebase/` docs.
56
+
57
+ ## Command Discovery
58
+
59
+ Run once per session and cache the result.
60
+
61
+ 1. Read `.buildwright/steering/tech.md` if it exists. If it has real commands,
62
+ use them.
63
+ 2. Otherwise auto-detect from project files in priority order:
64
+ `package.json`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `setup.py`,
65
+ `requirements.txt`, `Makefile`.
66
+ 3. Derive typecheck, lint, test, build, and dev commands. Mark unavailable
67
+ gates as `SKIP`.
68
+ 4. Write discovered commands to `.buildwright/steering/tech.md`.
69
+ 5. If still ambiguous, ask for the missing commands.
70
+
71
+ ## Operating Mode
72
+
73
+ - Execute autonomously unless information is genuinely missing.
74
+ - Verify your own work through tests and checks.
75
+ - Commit only after verification passes.
76
+ - Stop only when genuinely blocked.
77
+
78
+ `BUILDWRIGHT_AUTO_APPROVE=true` means autonomous mode. If a step fails after
79
+ retries, commit completed work, push, create a PR with failure details, and
80
+ exit non-zero. In interactive mode (`BUILDWRIGHT_AUTO_APPROVE=false`), stop and
81
+ report the blocker.
82
+
83
+ ## Verification Loop
84
+
85
+ Before every commit, run discovered gates:
86
+
87
+ 1. Typecheck
88
+ 2. Lint
89
+ 3. Test
90
+ 4. Build
91
+
92
+ Skip only gates that are unavailable for the stack. If a required step fails,
93
+ fix and retry up to `BUILDWRIGHT_AGENT_RETRIES` times, default 2.
94
+
95
+ ## Documentation Discipline
96
+
97
+ Documentation is part of done.
98
+
99
+ Before every commit, update affected README, docs, command text, API docs,
100
+ examples, changelog, or generated user-facing docs. If no docs need updating,
101
+ say why in the final report.
102
+
103
+ ## Git Rules
104
+
105
+ - Atomic commits: only commit files you changed.
106
+ - Conventional commits: `feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:`.
107
+ - Never edit `.env` files.
108
+ - Never run destructive git operations without explicit instruction.
109
+ - Never use `git stash`.
110
+ - `.buildwright/` and the root `AGENTS.md` are canonical and committed.
111
+ `CLAUDE.md` is a committed pointer stub. Do not commit generated `.claude/`,
112
+ `.opencode/`, `.cursor/rules/`, or `skills/`.
113
+ - After editing `.buildwright/`, run `make sync`.
114
+
115
+ ## Philosophy
116
+
117
+ Always apply `.buildwright/steering/philosophy.md`: KISS, YAGNI, DRY, boring
118
+ technology, fail fast, Red -> Green -> Refactor, and documentation discipline.
119
+
120
+ ## Self-Improvement
121
+
122
+ When you discover a reusable pattern or gotcha, add it below.
123
+
124
+ ## Learned Patterns
125
+
126
+ <!-- Agent adds entries here as it learns -->
@@ -1,123 +1,7 @@
1
- # Buildwright Development
1
+ # Buildwright
2
2
 
3
- ## Mission
3
+ Project instructions for all AI assistants live in **AGENTS.md** at the repo
4
+ root. Read that file.
4
5
 
5
- Agent-first disciplined development. Humans approve intent when needed; agents
6
- understand, test, implement, document, verify, review, and ship.
7
-
8
- ## Steering Documents
9
-
10
- At the start of every session, recursively discover and read all `.md` files
11
- under `.buildwright/steering/`. Use:
12
-
13
- ```bash
14
- find .buildwright/steering -type f -name "*.md" | sort
15
- ```
16
-
17
- The default steering file is `philosophy.md`.
18
-
19
- Also recursively read all `.md` files under `.buildwright/codebase/` if that
20
- directory exists. These are codebase analysis docs generated by `/bw-analyse`.
21
-
22
- Do not assume a fixed set of project steering files. `tech.md` and `product.md`
23
- are created only when Buildwright has real project-specific content.
24
-
25
- ## Project Structure
26
-
27
- `.buildwright/` is the canonical configuration directory committed to git.
28
- Tool-specific directories are generated from it and gitignored:
29
-
30
- ```
31
- .buildwright/
32
- agents/ # Staff Engineer, Security Engineer
33
- codebase/ # Generated by /bw-analyse
34
- commands/ # bw-work, bw-plan, bw-verify, bw-ship, bw-analyse
35
- steering/ # philosophy.md plus lazy-created tech.md/product.md
36
-
37
- .claude/ # Generated by make sync
38
- .opencode/ # Generated by make sync
39
- .cursor/rules/ # Generated by make sync
40
- AGENTS.md # Generated by make sync
41
- ```
42
-
43
- After cloning or editing `.buildwright/`, run `make sync`.
44
-
45
- ## Commands
46
-
47
- Use the smallest command that matches the intent:
48
-
49
- 1. `/bw-plan` — think/research only; no code changes, commits, or PRs.
50
- 2. `/bw-work` — implement bug fixes, refactors, and features.
51
- 3. `/bw-verify` — run typecheck, lint, test, and build gates.
52
- 4. `/bw-ship` — verify, security review, code review, push, and PR.
53
- 5. `/bw-analyse` — analyse brownfield codebases and write `.buildwright/codebase/` docs.
54
-
55
- ## Command Discovery
56
-
57
- Run once per session and cache the result.
58
-
59
- 1. Read `.buildwright/steering/tech.md` if it exists. If it has real commands,
60
- use them.
61
- 2. Otherwise auto-detect from project files in priority order:
62
- `package.json`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `setup.py`,
63
- `requirements.txt`, `Makefile`.
64
- 3. Derive typecheck, lint, test, build, and dev commands. Mark unavailable
65
- gates as `SKIP`.
66
- 4. Write discovered commands to `.buildwright/steering/tech.md`.
67
- 5. If still ambiguous, ask for the missing commands.
68
-
69
- ## Operating Mode
70
-
71
- - Execute autonomously unless information is genuinely missing.
72
- - Verify your own work through tests and checks.
73
- - Commit only after verification passes.
74
- - Stop only when genuinely blocked.
75
-
76
- `BUILDWRIGHT_AUTO_APPROVE=true` means autonomous mode. If a step fails after
77
- retries, commit completed work, push, create a PR with failure details, and
78
- exit non-zero. In interactive mode (`BUILDWRIGHT_AUTO_APPROVE=false`), stop and
79
- report the blocker.
80
-
81
- ## Verification Loop
82
-
83
- Before every commit, run discovered gates:
84
-
85
- 1. Typecheck
86
- 2. Lint
87
- 3. Test
88
- 4. Build
89
-
90
- Skip only gates that are unavailable for the stack. If a required step fails,
91
- fix and retry up to `BUILDWRIGHT_AGENT_RETRIES` times, default 2.
92
-
93
- ## Documentation Discipline
94
-
95
- Documentation is part of done.
96
-
97
- Before every commit, update affected README, docs, command text, API docs,
98
- examples, changelog, or generated user-facing docs. If no docs need updating,
99
- say why in the final report.
100
-
101
- ## Git Rules
102
-
103
- - Atomic commits: only commit files you changed.
104
- - Conventional commits: `feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:`.
105
- - Never edit `.env` files.
106
- - Never run destructive git operations without explicit instruction.
107
- - Never use `git stash`.
108
- - Only `.buildwright/` is canonical. Do not commit generated `.claude/`,
109
- `.opencode/`, `.cursor/rules/`, `skills/`, or `AGENTS.md`.
110
- - After editing `.buildwright/`, run `make sync`.
111
-
112
- ## Philosophy
113
-
114
- Always apply `.buildwright/steering/philosophy.md`: KISS, YAGNI, DRY, boring
115
- technology, fail fast, Red -> Green -> Refactor, and documentation discipline.
116
-
117
- ## Self-Improvement
118
-
119
- When you discover a reusable pattern or gotcha, add it below.
120
-
121
- ## Learned Patterns
122
-
123
- <!-- Agent adds entries here as it learns -->
6
+ `AGENTS.md` is the single source of truth Claude Code, Codex, OpenCode, and
7
+ Cursor all consume it.
@@ -1,4 +1,4 @@
1
- .PHONY: dist clean sync sync-check cursor opencode openclaw codex validate install-hooks uninstall-hooks bump release test-cli
1
+ .PHONY: dist clean sync sync-check cursor claude opencode openclaw codex global validate install-hooks uninstall-hooks bump release test-cli
2
2
 
3
3
  # ============================================================================
4
4
  # Sync — Generate .claude/, .opencode/, .cursor/rules/ from .buildwright/ (canonical)
@@ -21,12 +21,27 @@ sync-check:
21
21
  dist: sync
22
22
  @echo "dist/buildwright/ ready — upload this folder to ClawHub"
23
23
 
24
+ # ============================================================================
25
+ # Global install — make the workflow available in every project, per tool.
26
+ # Each target installs into a user-level (~/...) location. `make global` runs
27
+ # them all. Project-specific steering still comes from each project's
28
+ # .buildwright/ (created by `buildwright init`).
29
+ # ============================================================================
30
+
24
31
  # Cursor — print setup instructions (rules generated by make sync)
25
32
  cursor: sync
26
33
  @echo "Cursor rules generated at .cursor/rules/"
27
34
  @echo "Open this project in Cursor — rules are applied automatically."
28
35
  @echo "Settings > Rules shows steering rules as 'Always' and commands/agents as 'Intelligent'."
29
36
 
37
+ # Claude Code — install commands + agents to user global config
38
+ claude: sync
39
+ @mkdir -p ~/.claude/commands ~/.claude/agents
40
+ @cp .claude/commands/bw-*.md ~/.claude/commands/
41
+ @cp .claude/agents/staff-engineer.md .claude/agents/security-engineer.md ~/.claude/agents/
42
+ @echo "Installed Buildwright commands + agents to ~/.claude/"
43
+ @echo "Restart Claude Code to discover /bw-* commands globally."
44
+
30
45
  # OpenCode — install skill to user global config
31
46
  opencode: sync
32
47
  @mkdir -p ~/.config/opencode/skills/buildwright
@@ -46,6 +61,10 @@ codex: sync
46
61
  @echo "Installed to ~/.agents/skills/buildwright"
47
62
  @echo "Restart Codex to discover Buildwright skills."
48
63
 
64
+ # Global — install across all supported tools in one step
65
+ global: claude codex opencode openclaw
66
+ @echo "Buildwright installed globally for Claude Code, Codex, OpenCode, and OpenClaw."
67
+
49
68
  # ============================================================================
50
69
  # Validate SKILL.md against Agent Skills spec (agentskills.io)
51
70
  # ============================================================================
@@ -12,9 +12,11 @@
12
12
  # .cursor/rules/steering/ ← .mdc files with alwaysApply: true
13
13
  # .cursor/rules/commands/ ← .mdc files with alwaysApply: false
14
14
  # .cursor/rules/agents/ ← .mdc files with alwaysApply: false
15
- # AGENTS.md ← CLAUDE.md with OpenCode header prepended
16
15
  # dist/buildwright/ ← SKILL.md packaged for ClawHub
17
16
  #
17
+ # Note: AGENTS.md (canonical, committed) and CLAUDE.md (pointer stub) are NOT
18
+ # generated — they are hand-maintained root files.
19
+ #
18
20
  # Usage: scripts/sync-agents.sh [--check]
19
21
  # --check: Verify sync without modifying files (exit 1 if out of sync)
20
22
 
@@ -129,9 +131,23 @@ set_cursor_frontmatter() {
129
131
  esac
130
132
  }
131
133
 
134
+ # strip_frontmatter FILE
135
+ # Emits FILE's body with a leading YAML frontmatter block (--- ... ---) removed.
136
+ # Files without frontmatter are emitted unchanged. Cursor .mdc files carry their
137
+ # own frontmatter, so the source's name/description block must not leak into the
138
+ # rule body.
139
+ strip_frontmatter() {
140
+ awk '
141
+ NR==1 && $0=="---" { in_fm=1; next }
142
+ in_fm && $0=="---" { in_fm=0; next }
143
+ !in_fm { print }
144
+ ' "$1"
145
+ }
146
+
132
147
  # sync_cursor_dir SRC DST_SUBDIR PRESET
133
148
  # Converts .md files in SRC to .mdc files in .cursor/rules/DST_SUBDIR,
134
149
  # prepending YAML frontmatter and rewriting @.buildwright/ → @.cursor/rules/.
150
+ # The source's own frontmatter (if any) is stripped first.
135
151
  # Skips README and TEMPLATE files.
136
152
  sync_cursor_dir() {
137
153
  local src="$1"
@@ -178,7 +194,7 @@ sync_cursor_dir() {
178
194
  printf '%s\n' "globs: []"
179
195
  printf 'alwaysApply: %s\n' "$CURSOR_ALWAYS_APPLY"
180
196
  printf '%s\n' "---"
181
- sed 's|@\.buildwright/|@.cursor/rules/|g' "$src_file"
197
+ strip_frontmatter "$src_file" | sed 's|@\.buildwright/|@.cursor/rules/|g'
182
198
  } > "$tmpfile"
183
199
  if ! diff -q "$dst_file" "$tmpfile" > /dev/null 2>&1; then
184
200
  echo "OUT OF SYNC: $dst_file"
@@ -194,7 +210,7 @@ sync_cursor_dir() {
194
210
  printf '%s\n' "globs: []"
195
211
  printf 'alwaysApply: %s\n' "$CURSOR_ALWAYS_APPLY"
196
212
  printf '%s\n' "---"
197
- sed 's|@\.buildwright/|@.cursor/rules/|g' "$src_file"
213
+ strip_frontmatter "$src_file" | sed 's|@\.buildwright/|@.cursor/rules/|g'
198
214
  } > "$dst_file"
199
215
  fi
200
216
  done < <(find "$src" -type f -name "*.md" | sort)
@@ -230,40 +246,7 @@ sync_dir ".buildwright/steering" ".opencode/steering"
230
246
  sync_dir ".buildwright/codebase" ".opencode/codebase"
231
247
 
232
248
  # ============================================================================
233
- # 3. CLAUDE.mdAGENTS.md
234
- # ============================================================================
235
-
236
- generate_agents_md() {
237
- local target="$1"
238
- printf '%s\n' "---" \
239
- "# OpenCode agent instructions" \
240
- "# Auto-generated from CLAUDE.md — do not edit directly" \
241
- "# Run: scripts/sync-agents.sh to regenerate" \
242
- "---" \
243
- "" > "$target"
244
- cat CLAUDE.md >> "$target"
245
- }
246
-
247
- if [ "$CHECK_ONLY" = true ]; then
248
- if [ ! -f "AGENTS.md" ]; then
249
- echo "MISSING: AGENTS.md (should be generated from CLAUDE.md)"
250
- SYNC_NEEDED=true
251
- else
252
- TMPFILE=$(mktemp)
253
- generate_agents_md "$TMPFILE"
254
- if ! diff -q "AGENTS.md" "$TMPFILE" > /dev/null 2>&1; then
255
- echo "OUT OF SYNC: AGENTS.md differs from CLAUDE.md"
256
- SYNC_NEEDED=true
257
- fi
258
- rm -f "$TMPFILE"
259
- fi
260
- else
261
- generate_agents_md "AGENTS.md"
262
- echo " generated AGENTS.md from CLAUDE.md"
263
- fi
264
-
265
- # ============================================================================
266
- # 4. .buildwright/ → .cursor/rules/ (convert to .mdc with frontmatter)
249
+ # 3. .buildwright/ → .cursor/rules/ (convert to .mdc with frontmatter)
267
250
  # ============================================================================
268
251
 
269
252
  sync_cursor_dir ".buildwright/steering" "steering" "steering"
@@ -272,7 +255,7 @@ sync_cursor_dir ".buildwright/commands" "commands" "command"
272
255
  sync_cursor_dir ".buildwright/agents" "agents" "agent"
273
256
 
274
257
  # ============================================================================
275
- # 5. .buildwright/commands/ → skills/ (Codex CLI skill discovery)
258
+ # 4. .buildwright/commands/ → skills/ (Codex CLI skill discovery)
276
259
  # ============================================================================
277
260
 
278
261
  if [ "$CHECK_ONLY" = false ]; then
@@ -287,7 +270,7 @@ if [ "$CHECK_ONLY" = false ]; then
287
270
  fi
288
271
 
289
272
  # ============================================================================
290
- # 6. Package for ClawHub (dist/)
273
+ # 5. Package for ClawHub (dist/)
291
274
  # ============================================================================
292
275
 
293
276
  if [ "$CHECK_ONLY" = false ] && [ -f "SKILL.md" ]; then
@@ -297,7 +280,7 @@ if [ "$CHECK_ONLY" = false ] && [ -f "SKILL.md" ]; then
297
280
  fi
298
281
 
299
282
  # ============================================================================
300
- # 7. README.md → cli/README.md (single source of truth for npm package page)
283
+ # 6. README.md → cli/README.md (single source of truth for npm package page)
301
284
  # Only runs in the buildwright repo itself, which has a cli/ directory.
302
285
  # Generated services do not have cli/ and must not fail here.
303
286
  # ============================================================================
@@ -326,7 +309,6 @@ else
326
309
  echo " .buildwright/ → .claude/ (paths rewritten)"
327
310
  echo " .buildwright/ → .opencode/ (paths rewritten)"
328
311
  echo " .buildwright/ → .cursor/rules/ (.mdc with frontmatter)"
329
- echo " CLAUDE.md → AGENTS.md"
330
312
  echo " SKILL.md → dist/buildwright/SKILL.md"
331
313
  echo " .buildwright/commands/ → skills/ (Codex CLI skill discovery)"
332
314
  if [ -d "cli" ]; then