@keighleykodric/weeve 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -11
- package/bin/weeve.js +452 -2
- package/examples/core/CODEOWNERS.template +9 -0
- package/examples/core/README.md +63 -0
- package/examples/core/demo/README.md +38 -0
- package/examples/core/demo/weeve/ally/ally-intake.md +16 -0
- package/examples/core/demo/weeve/compass/compass-intake.md +15 -0
- package/examples/core/demo/weeve/layers-plus/figma-notes.md +31 -0
- package/examples/core/demo/weeve/layers-plus/layers-plus-intake.md +13 -0
- package/examples/core/demo/weeve/rubric/component-inventory.md +42 -0
- package/examples/core/demo/weeve/rubric/rubric-intake.md +14 -0
- package/examples/core/demo/weeve/shared/competitive.md +28 -0
- package/examples/core/demo/weeve/shared/roadmap.md +26 -0
- package/examples/core/demo/weeve/shared/weeve-guardrails.md +28 -0
- package/examples/core/demo/weeve/shared/weeve-intake.md +18 -0
- package/examples/core/demo/weeve/shared/weeve-project.md +33 -0
- package/examples/core/demo/weeve.yaml +15 -0
- package/examples/core/weeve.yaml +14 -0
- package/examples/engineering/CODEOWNERS.template +9 -0
- package/examples/engineering/README.md +61 -0
- package/examples/engineering/demo/README.md +20 -0
- package/examples/engineering/demo/weeve/forge/architecture.md +39 -0
- package/examples/engineering/demo/weeve/forge/ci-metrics.md +47 -0
- package/examples/engineering/demo/weeve/forge/forge-intake.md +41 -0
- package/examples/engineering/demo/weeve/guard/guard-intake.md +17 -0
- package/examples/engineering/demo/weeve/helm/helm-intake.md +16 -0
- package/examples/engineering/demo/weeve/helm/incidents.md +40 -0
- package/examples/engineering/demo/weeve/helm/on-call-runbook.md +33 -0
- package/examples/engineering/demo/weeve/shared/roadmap.md +25 -0
- package/examples/engineering/demo/weeve/shared/team.md +33 -0
- package/examples/engineering/demo/weeve/shared/weeve-guardrails.md +27 -0
- package/examples/engineering/demo/weeve/shared/weeve-intake.md +18 -0
- package/examples/engineering/demo/weeve/shared/weeve-project.md +29 -0
- package/examples/engineering/demo/weeve/verify/coverage-report.md +49 -0
- package/examples/engineering/demo/weeve/verify/verify-intake.md +16 -0
- package/examples/engineering/demo/weeve.yaml +15 -0
- package/examples/engineering/weeve.yaml +14 -0
- package/examples/gtm/CODEOWNERS.template +8 -0
- package/examples/gtm/README.md +59 -0
- package/examples/gtm/demo/README.md +19 -0
- package/examples/gtm/demo/weeve/compass/compass-intake.md +15 -0
- package/examples/gtm/demo/weeve/maven/maven-intake.md +35 -0
- package/examples/gtm/demo/weeve/maven/website-notes.md +33 -0
- package/examples/gtm/demo/weeve/pitch/pitch-intake.md +54 -0
- package/examples/gtm/demo/weeve/pitch/sales-deck-notes.md +28 -0
- package/examples/gtm/demo/weeve/pitch/win-loss-notes.md +40 -0
- package/examples/gtm/demo/weeve/shared/competitive.md +30 -0
- package/examples/gtm/demo/weeve/shared/roadmap.md +19 -0
- package/examples/gtm/demo/weeve/shared/weeve-guardrails.md +24 -0
- package/examples/gtm/demo/weeve/shared/weeve-intake.md +18 -0
- package/examples/gtm/demo/weeve/shared/weeve-project.md +25 -0
- package/examples/gtm/demo/weeve.yaml +22 -0
- package/examples/gtm/weeve.yaml +14 -0
- package/examples/product/CODEOWNERS.template +10 -0
- package/examples/product/README.md +67 -0
- package/examples/product/demo/README.md +21 -0
- package/examples/product/demo/weeve/ally/ally-intake.md +16 -0
- package/examples/product/demo/weeve/compass/compass-intake.md +15 -0
- package/examples/product/demo/weeve/felt/felt-intake.md +37 -0
- package/examples/product/demo/weeve/felt/user-research.md +68 -0
- package/examples/product/demo/weeve/layers-plus/layers-plus-intake.md +14 -0
- package/examples/product/demo/weeve/rubric/component-inventory.md +42 -0
- package/examples/product/demo/weeve/rubric/rubric-intake.md +14 -0
- package/examples/product/demo/weeve/shared/competitive.md +28 -0
- package/examples/product/demo/weeve/shared/roadmap.md +32 -0
- package/examples/product/demo/weeve/shared/weeve-guardrails.md +27 -0
- package/examples/product/demo/weeve/shared/weeve-intake.md +18 -0
- package/examples/product/demo/weeve/shared/weeve-project.md +29 -0
- package/examples/product/demo/weeve.yaml +21 -0
- package/examples/product/weeve.yaml +14 -0
- package/examples/strategy/CODEOWNERS.template +8 -0
- package/examples/strategy/README.md +59 -0
- package/examples/strategy/demo/README.md +19 -0
- package/examples/strategy/demo/weeve/compass/compass-intake.md +34 -0
- package/examples/strategy/demo/weeve/compass/customer-segments.md +34 -0
- package/examples/strategy/demo/weeve/layers-plus/layers-plus-intake.md +15 -0
- package/examples/strategy/demo/weeve/maven/maven-intake.md +33 -0
- package/examples/strategy/demo/weeve/shared/competitive.md +40 -0
- package/examples/strategy/demo/weeve/shared/roadmap.md +29 -0
- package/examples/strategy/demo/weeve/shared/weeve-guardrails.md +22 -0
- package/examples/strategy/demo/weeve/shared/weeve-intake.md +17 -0
- package/examples/strategy/demo/weeve/shared/weeve-project.md +25 -0
- package/examples/strategy/demo/weeve.yaml +15 -0
- package/examples/strategy/weeve.yaml +14 -0
- package/package.json +14 -3
- package/{reference → spec}/contributing-template.md +5 -4
- package/{reference → spec}/readme-template.md +4 -4
- package/{reference → spec}/ship-gate.md +7 -7
- package/spec/signals-schema.md +685 -0
- package/spec/weeve-yaml.md +274 -0
- package/.github/SECURITY.md +0 -22
- package/GOVERNANCE.md +0 -173
- package/WORKFLOW.md +0 -354
- package/reference/conventions.md +0 -237
- package/reference/engineering-contract.md +0 -94
- package/reference/id-prefixes.md +0 -235
- package/reference/intake-pattern.md +0 -99
- package/reference/schema.md +0 -363
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# 🧵 Weeve
|
|
2
2
|
|
|
3
|
-
Cross-functional
|
|
3
|
+
Cross-functional contract framework. Each domain writes findings in the same versioned schema shape — Pilot reads them all and surfaces what conflicts, what blocks the ship, and what to do first. Observability for AI-orchestrated execution.
|
|
4
4
|
|
|
5
|
-
Markdown-in-git. BYO everything.
|
|
5
|
+
Markdown-in-git. BYO everything. The contract shape is the durable asset: a versioned schema that every lane writes to and Pilot synthesizes from. Findings from different domains compose because they share a common structure — not because a platform forces alignment.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -10,9 +10,9 @@ Markdown-in-git. BYO everything. Each lane writes a `<lane>-recommendations.md`
|
|
|
10
10
|
|
|
11
11
|
1. Install the lanes you need
|
|
12
12
|
2. Run each lane against your product (`/<lane>-intro` to start)
|
|
13
|
-
3. Each lane writes findings to `docs/<lane>/<lane>-
|
|
14
|
-
4. Run `/pilot-
|
|
15
|
-
5. Run `/pilot-ship` — autonomous worker picks tasks from the
|
|
13
|
+
3. Each lane writes findings to `docs/<lane>/<lane>-signals.md`
|
|
14
|
+
4. Run `/pilot-priorities` — Pilot reads all lane outputs and synthesizes a prioritized backlog
|
|
15
|
+
5. Run `/pilot-ship` — autonomous worker picks tasks from the priorities file and ships them
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -66,9 +66,13 @@ Markdown-in-git. BYO everything. Each lane writes a `<lane>-recommendations.md`
|
|
|
66
66
|
|
|
67
67
|
---
|
|
68
68
|
|
|
69
|
+
> **Trust model:** Skills execute with your OS permissions — only install from trusted sources.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
69
73
|
## You don't need every lane
|
|
70
74
|
|
|
71
|
-
Install only the lanes that match your team. If marketing doesn't use Maven, that's fine — Maven won't appear in the Pilot
|
|
75
|
+
Install only the lanes that match your team. If marketing doesn't use Maven, that's fine — Maven won't appear in the Pilot priorities file, and nothing breaks.
|
|
72
76
|
|
|
73
77
|
Departments without a lane can still contribute. Any team member can feed context into another lane's intake skill — paste a doc, a ticket link, or a screenshot into `/compass-intake` or `/layers-plus-intake` and it gets scoped and routed. You don't need a lane installed to provide input; you just won't get lane-specific findings back.
|
|
74
78
|
|
|
@@ -96,6 +100,16 @@ npx @keighleykodric/weeve add all # Everything
|
|
|
96
100
|
|
|
97
101
|
Every preset includes Pilot — it's the synthesis layer that makes the lanes compose.
|
|
98
102
|
|
|
103
|
+
### Version pinning
|
|
104
|
+
|
|
105
|
+
Pin to a tagged release for reproducible installs:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
npx skills add keighleykodric/weeve-compass@v0.1.0
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
See [Releases](https://github.com/keighleykodric/weeve/releases) for available versions.
|
|
112
|
+
|
|
99
113
|
---
|
|
100
114
|
|
|
101
115
|
## First-run order
|
|
@@ -106,22 +120,64 @@ See [WORKFLOW.md](WORKFLOW.md) for the full cadence, within-lane sequences, and
|
|
|
106
120
|
|
|
107
121
|
---
|
|
108
122
|
|
|
109
|
-
## The
|
|
123
|
+
## The contract shape
|
|
110
124
|
|
|
111
|
-
Each lane writes findings independently. Pilot reads them all and surfaces:
|
|
125
|
+
Each lane writes findings independently, in the same schema. Pilot reads them all and surfaces:
|
|
112
126
|
- Cross-lane conflicts (strategy says X, design says Y)
|
|
113
127
|
- Ship gates (Guard or Verify can block `/pilot-ship`)
|
|
114
128
|
- Priority synthesis (what to do first, across all domains)
|
|
115
129
|
|
|
116
|
-
The
|
|
130
|
+
The schema is what makes the lanes composable. A finding from Guard and a finding from Compass use the same severity vocabulary, status field, and ID prefix — so Pilot can synthesize them without translation. The contract is the moat, not the lane count.
|
|
117
131
|
|
|
118
132
|
---
|
|
119
133
|
|
|
120
134
|
## Schema
|
|
121
135
|
|
|
122
|
-
All lane
|
|
136
|
+
All lane signals files follow a versioned schema: [signals-schema.md](spec/schema.md) (v0.4).
|
|
137
|
+
|
|
138
|
+
The schema is the contract. Severity uses `🔴 High / 🟡 Medium / 🟢 Low`. Lane files never use Now/Next/Watch — that vocabulary belongs to Pilot's priorities output. The manifest hierarchy (`weeve.yaml` → `road.yaml` → `lane.yaml`) governs multi-lane configuration.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Alternative installation (git clone)
|
|
143
|
+
|
|
144
|
+
If you prefer not to use the npm installer, you can clone lanes directly and verify integrity:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Clone a specific tagged release
|
|
148
|
+
git clone --branch v0.1.0 --depth 1 https://github.com/keighleykodric/weeve-compass.git
|
|
149
|
+
|
|
150
|
+
# Verify the commit SHA matches the published release
|
|
151
|
+
cd weeve-compass
|
|
152
|
+
git rev-parse HEAD
|
|
153
|
+
# Compare against the SHA listed on https://github.com/keighleykodric/weeve-compass/releases/tag/v0.1.0
|
|
154
|
+
|
|
155
|
+
# Verify skills-lock.json integrity (if present)
|
|
156
|
+
# skills-lock.json contains SHA-256 hashes of all SKILL.md files
|
|
157
|
+
cat skills-lock.json
|
|
158
|
+
# Manually verify: shasum -a 256 skills/<skill-dir>/SKILL.md
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Then symlink or copy the skills directory into `~/.claude/skills/`:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
cp -r skills/* ~/.claude/skills/
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
This bypasses the npm registry entirely. You can audit all code before installation and verify that file contents match the published hashes in `skills-lock.json`.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Terminology
|
|
172
|
+
|
|
173
|
+
Two terms in Weave overlap with common engineering vocabulary:
|
|
174
|
+
|
|
175
|
+
| Term | In Weave | In engineering contexts |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| **Operator** | The practitioner running the lanes — a cross-functional lead, designer, or strategist using Claude Code | Infrastructure operator, DevOps engineer, Kubernetes operator |
|
|
178
|
+
| **Schema** | The governance spec that defines how lanes write findings (`spec/schema.md`) | Database schema, OpenAPI spec, JSON Schema |
|
|
123
179
|
|
|
124
|
-
|
|
180
|
+
If you come from an infrastructure or data engineering background: Weave's "Operator" is closer to "practitioner" or "user," and Weave's "Schema" is closer to "contract format" or "output spec."
|
|
125
181
|
|
|
126
182
|
---
|
|
127
183
|
|
package/bin/weeve.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const { execSync } = require("child_process");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const os = require("os");
|
|
4
7
|
|
|
5
8
|
const ORG = "keighleykodric";
|
|
6
9
|
|
|
@@ -37,6 +40,27 @@ const PRESETS = {
|
|
|
37
40
|
gtm: ["compass", "maven", "pitch", "pilot"],
|
|
38
41
|
};
|
|
39
42
|
|
|
43
|
+
// CODEOWNERS lines per lane
|
|
44
|
+
const LANE_OWNERS = {
|
|
45
|
+
compass: "weeve/compass/ @leadership",
|
|
46
|
+
"layers-plus": "weeve/layers-plus/ @product",
|
|
47
|
+
felt: "weeve/felt/ @product",
|
|
48
|
+
ally: "weeve/ally/ @design",
|
|
49
|
+
rubric: "weeve/rubric/ @design",
|
|
50
|
+
forge: "weeve/forge/ @engineering",
|
|
51
|
+
helm: "weeve/helm/ @engineering",
|
|
52
|
+
verify: "weeve/verify/ @engineering",
|
|
53
|
+
guard: "weeve/guard/ @security",
|
|
54
|
+
maven: "weeve/maven/ @marketing",
|
|
55
|
+
pitch: "weeve/pitch/ @revenue",
|
|
56
|
+
pilot: "weeve/pilot/ @leadership",
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const FIRST_STEP_ORDER = [
|
|
60
|
+
"compass", "layers-plus", "felt", "ally", "rubric",
|
|
61
|
+
"forge", "helm", "verify", "guard", "maven", "pitch", "pilot",
|
|
62
|
+
];
|
|
63
|
+
|
|
40
64
|
const cmd = process.argv[2];
|
|
41
65
|
const args = process.argv.slice(3);
|
|
42
66
|
|
|
@@ -62,8 +86,9 @@ function installLanes(lanes) {
|
|
|
62
86
|
console.log(` + ${lane} — ${LANES[lane]}`);
|
|
63
87
|
run(`npx skills add ${repo}`);
|
|
64
88
|
}
|
|
89
|
+
// Always install framework skills from the weeve repo itself
|
|
90
|
+
run(`npx skills add ${ORG}/weeve`);
|
|
65
91
|
// Show the right first step based on what was installed
|
|
66
|
-
const FIRST_STEP_ORDER = ["compass", "layers-plus", "felt", "ally", "rubric", "forge", "helm", "verify", "guard", "maven", "pitch", "pilot"];
|
|
67
92
|
const firstLane = FIRST_STEP_ORDER.find((l) => lanes.includes(l));
|
|
68
93
|
if (firstLane && firstLane !== "pilot") {
|
|
69
94
|
console.log(`\nDone. Run /${firstLane}-intro to get started.`);
|
|
@@ -95,6 +120,421 @@ switch (cmd) {
|
|
|
95
120
|
break;
|
|
96
121
|
}
|
|
97
122
|
|
|
123
|
+
case "init": {
|
|
124
|
+
const presetArg = args[0];
|
|
125
|
+
|
|
126
|
+
// Resolve lanes to scaffold
|
|
127
|
+
let lanes;
|
|
128
|
+
if (!presetArg) {
|
|
129
|
+
lanes = Object.keys(LANES);
|
|
130
|
+
} else if (PRESETS[presetArg]) {
|
|
131
|
+
lanes = PRESETS[presetArg];
|
|
132
|
+
} else if (LANES[presetArg]) {
|
|
133
|
+
lanes = [presetArg];
|
|
134
|
+
} else {
|
|
135
|
+
console.error(`Unknown preset or lane: ${presetArg}`);
|
|
136
|
+
console.error(`Run 'weeve presets' to see available presets.`);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const cwd = process.cwd();
|
|
141
|
+
const yamlPath = path.join(cwd, "weeve.yaml");
|
|
142
|
+
|
|
143
|
+
// Bail if weeve.yaml already exists
|
|
144
|
+
if (fs.existsSync(yamlPath)) {
|
|
145
|
+
console.error(`Warning: weeve.yaml already exists in ${cwd}. Exiting without changes.`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 1. Create weeve/<lane>/ output folders
|
|
150
|
+
for (const lane of lanes) {
|
|
151
|
+
const laneDir = path.join(cwd, "weeve", lane);
|
|
152
|
+
fs.mkdirSync(laneDir, { recursive: true });
|
|
153
|
+
fs.writeFileSync(path.join(laneDir, ".gitkeep"), "");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// 1b. Create loom/ content-type folders based on installed lanes, plus shared/ and archive/
|
|
157
|
+
// Loom is organised by content type, not lane — multiple lanes share the same folder.
|
|
158
|
+
const loomFolders = new Set(["shared"]);
|
|
159
|
+
const LOOM_MAP = {
|
|
160
|
+
strategy: ["compass"],
|
|
161
|
+
business: ["compass", "guard"],
|
|
162
|
+
design: ["ally", "layers-plus", "rubric"],
|
|
163
|
+
engineering: ["forge", "helm", "verify", "guard", "layers-plus"],
|
|
164
|
+
research: ["felt"],
|
|
165
|
+
marketing: ["maven", "rubric"],
|
|
166
|
+
sales: ["pitch"],
|
|
167
|
+
};
|
|
168
|
+
for (const [folder, owners] of Object.entries(LOOM_MAP)) {
|
|
169
|
+
if (owners.some((l) => lanes.includes(l))) loomFolders.add(folder);
|
|
170
|
+
}
|
|
171
|
+
for (const folder of loomFolders) {
|
|
172
|
+
const dir = path.join(cwd, "loom", folder);
|
|
173
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
174
|
+
fs.writeFileSync(path.join(dir, ".gitkeep"), "");
|
|
175
|
+
}
|
|
176
|
+
fs.mkdirSync(path.join(cwd, "archive"), { recursive: true });
|
|
177
|
+
|
|
178
|
+
// 2. Write weeve.yaml
|
|
179
|
+
const projName = path.basename(cwd);
|
|
180
|
+
const projTag = projName.replace(/[^a-zA-Z0-9]/g, "").slice(0, 6).toUpperCase() || "MYP";
|
|
181
|
+
const yaml = [
|
|
182
|
+
`# weeve.yaml — generated by weeve init`,
|
|
183
|
+
`schema_version: "0.4"`,
|
|
184
|
+
``,
|
|
185
|
+
`project:`,
|
|
186
|
+
` name: ${projName}`,
|
|
187
|
+
` tag: ${projTag}`,
|
|
188
|
+
` # docs_root: ./weeve # Uncomment to write skill outputs here instead of vault`,
|
|
189
|
+
` # loom_root: ./loom # Uncomment to read raw input from here instead of vault`,
|
|
190
|
+
` # repos: # Multi-repo: list other repos that share this tag`,
|
|
191
|
+
` # - name: api`,
|
|
192
|
+
` # path: ../my-api`,
|
|
193
|
+
` # depends_on: # Other weeve projects this project reads context from`,
|
|
194
|
+
` # - tag: API`,
|
|
195
|
+
` # name: Core API`,
|
|
196
|
+
` # relationship: api-contract`,
|
|
197
|
+
``,
|
|
198
|
+
`roads:`,
|
|
199
|
+
` - name: startup`,
|
|
200
|
+
` path: roads/startup`,
|
|
201
|
+
``,
|
|
202
|
+
`# Installed lanes: ${lanes.join(", ")}`,
|
|
203
|
+
`# Run 'weeve status' to see installed skills`,
|
|
204
|
+
``,
|
|
205
|
+
].join("\n");
|
|
206
|
+
fs.writeFileSync(yamlPath, yaml);
|
|
207
|
+
|
|
208
|
+
// 3a. Scaffold weeve/shared/ for skill-managed shared docs
|
|
209
|
+
const sharedDir = path.join(cwd, "weeve", "shared");
|
|
210
|
+
fs.mkdirSync(sharedDir, { recursive: true });
|
|
211
|
+
|
|
212
|
+
fs.writeFileSync(path.join(sharedDir, "weeve-project.md"), [
|
|
213
|
+
`# ${projName} — project brief`,
|
|
214
|
+
``,
|
|
215
|
+
`<!-- What are you building, who is it for, what stage are you at? -->`,
|
|
216
|
+
`<!-- Include: product surface, current state, team size, open questions -->`,
|
|
217
|
+
``,
|
|
218
|
+
`**What it is:**`,
|
|
219
|
+
``,
|
|
220
|
+
`**Stage:**`,
|
|
221
|
+
``,
|
|
222
|
+
`**Core surface:**`,
|
|
223
|
+
``,
|
|
224
|
+
`**Current state:**`,
|
|
225
|
+
``,
|
|
226
|
+
`**Team:**`,
|
|
227
|
+
``,
|
|
228
|
+
`**Open questions:**`,
|
|
229
|
+
``,
|
|
230
|
+
].join("\n"));
|
|
231
|
+
|
|
232
|
+
fs.writeFileSync(path.join(sharedDir, "weeve-decisions.md"), [
|
|
233
|
+
`# ${projName} — key decisions`,
|
|
234
|
+
``,
|
|
235
|
+
`<!-- Architectural, product, and strategic decisions that are settled.`,
|
|
236
|
+
` Lanes use this to avoid re-opening closed questions. -->`,
|
|
237
|
+
`<!-- Format: - [DATE] Decision. Reason. -->`,
|
|
238
|
+
``,
|
|
239
|
+
].join("\n"));
|
|
240
|
+
|
|
241
|
+
fs.writeFileSync(path.join(sharedDir, "weeve-guardrails.md"), [
|
|
242
|
+
`# ${projName} — constraints`,
|
|
243
|
+
``,
|
|
244
|
+
`<!-- Hard limits and non-negotiables. Lanes treat these as guardrails. -->`,
|
|
245
|
+
`<!-- Pilot and all lanes read this before picking or executing tasks. -->`,
|
|
246
|
+
`<!-- Examples: no external SaaS without security review, must pass WCAG AA, -->`,
|
|
247
|
+
`<!-- no breaking API changes without deprecation period -->`,
|
|
248
|
+
``,
|
|
249
|
+
].join("\n"));
|
|
250
|
+
|
|
251
|
+
fs.writeFileSync(path.join(sharedDir, "weeve-sources.md"), [
|
|
252
|
+
`# ${projName} — context sources`,
|
|
253
|
+
``,
|
|
254
|
+
`<!-- Links to external docs lanes should be aware of. -->`,
|
|
255
|
+
`<!-- Org strategy, brand guidelines, API contracts, compliance docs, etc. -->`,
|
|
256
|
+
`<!-- Format: - **Label:** [Title](url) — one-line description -->`,
|
|
257
|
+
``,
|
|
258
|
+
].join("\n"));
|
|
259
|
+
|
|
260
|
+
// 3. Write or append CODEOWNERS
|
|
261
|
+
const codeownersPath = path.join(cwd, "CODEOWNERS");
|
|
262
|
+
const ownerLines = lanes
|
|
263
|
+
.filter((l) => LANE_OWNERS[l])
|
|
264
|
+
.map((l) => LANE_OWNERS[l]);
|
|
265
|
+
const codeownersBlock = [
|
|
266
|
+
`# Weeve lane ownership — edit to match your team structure`,
|
|
267
|
+
...ownerLines,
|
|
268
|
+
``,
|
|
269
|
+
].join("\n");
|
|
270
|
+
|
|
271
|
+
if (fs.existsSync(codeownersPath)) {
|
|
272
|
+
fs.appendFileSync(codeownersPath, "\n" + codeownersBlock);
|
|
273
|
+
} else {
|
|
274
|
+
fs.writeFileSync(codeownersPath, codeownersBlock);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// 4. Summary
|
|
278
|
+
const firstLane = FIRST_STEP_ORDER.find((l) => lanes.includes(l));
|
|
279
|
+
const nextCmd = firstLane && firstLane !== "pilot"
|
|
280
|
+
? `/${firstLane}-intro`
|
|
281
|
+
: `/pilot-intro`;
|
|
282
|
+
|
|
283
|
+
console.log(`\nWeeve initialized${presetArg ? ` (${presetArg} preset)` : ""}:\n`);
|
|
284
|
+
console.log(` Created weeve.yaml`);
|
|
285
|
+
console.log(` Created CODEOWNERS${fs.existsSync(codeownersPath) ? " (appended)" : ""}`);
|
|
286
|
+
console.log(` Created weeve/shared/weeve-project.md`);
|
|
287
|
+
console.log(` Created weeve/shared/weeve-decisions.md`);
|
|
288
|
+
console.log(` Created weeve/shared/weeve-guardrails.md`);
|
|
289
|
+
console.log(` Created weeve/shared/weeve-sources.md`);
|
|
290
|
+
console.log(` Created archive/`);
|
|
291
|
+
for (const lane of lanes) {
|
|
292
|
+
console.log(` Created weeve/${lane}/`);
|
|
293
|
+
}
|
|
294
|
+
const loomList = [...loomFolders].filter((f) => f !== "shared").sort().join("/ loom/");
|
|
295
|
+
console.log(` Created loom/${loomList}/ loom/shared/`);
|
|
296
|
+
console.log(`\n weeve/ — skill outputs (written by skills)`);
|
|
297
|
+
console.log(` loom/ — your input: drop notes, research, briefs here (organised by content type)`);
|
|
298
|
+
console.log(` archive/ — historical snapshots\n`);
|
|
299
|
+
console.log(`\nNext: run 'weeve add ${presetArg || "all"}' to install skills, then run ${nextCmd}\n`);
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
case "status": {
|
|
304
|
+
const lockPath = path.join(os.homedir(), ".claude", "skills-lock.json");
|
|
305
|
+
|
|
306
|
+
if (!fs.existsSync(lockPath)) {
|
|
307
|
+
console.log("No weeve lanes installed. Run 'weeve add <lane>' to get started.");
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
let lock;
|
|
312
|
+
try {
|
|
313
|
+
lock = JSON.parse(fs.readFileSync(lockPath, "utf8"));
|
|
314
|
+
} catch {
|
|
315
|
+
console.error(`Could not parse ${lockPath}`);
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const skills = lock.skills || {};
|
|
320
|
+
|
|
321
|
+
// Group skills by weeve lane (source matches keighleykodric/weeve-<lane>)
|
|
322
|
+
const laneMap = {};
|
|
323
|
+
for (const [skillName, skillData] of Object.entries(skills)) {
|
|
324
|
+
const source = skillData.source || "";
|
|
325
|
+
const match = source.match(/^keighleykodric\/weeve-(.+)$/);
|
|
326
|
+
if (match) {
|
|
327
|
+
const lane = match[1];
|
|
328
|
+
if (!laneMap[lane]) {
|
|
329
|
+
laneMap[lane] = { count: 0, source };
|
|
330
|
+
}
|
|
331
|
+
laneMap[lane].count++;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (Object.keys(laneMap).length === 0) {
|
|
336
|
+
console.log("No weeve lanes installed. Run 'weeve add <lane>' to get started.");
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
console.log("\nInstalled lanes:\n");
|
|
341
|
+
const laneNames = Object.keys(laneMap);
|
|
342
|
+
const maxLane = Math.max(...laneNames.map((l) => l.length));
|
|
343
|
+
for (const lane of laneNames) {
|
|
344
|
+
const { count, source } = laneMap[lane];
|
|
345
|
+
console.log(
|
|
346
|
+
` ${lane.padEnd(maxLane + 2)}${String(count).padStart(2)} skills ${source}`
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const firstInstalled = FIRST_STEP_ORDER.find((l) => laneMap[l]);
|
|
351
|
+
const nextCmd = firstInstalled && firstInstalled !== "pilot"
|
|
352
|
+
? `/${firstInstalled}-intro`
|
|
353
|
+
: `/pilot-intro`;
|
|
354
|
+
|
|
355
|
+
console.log(`\n${laneNames.length} lane${laneNames.length !== 1 ? "s" : ""} installed. Run ${nextCmd} to get started.\n`);
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
case "remove":
|
|
360
|
+
case "uninstall": {
|
|
361
|
+
if (!args.length) {
|
|
362
|
+
console.error("Usage: weeve remove <lane|preset> [lane2...]");
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Expand preset or validate individual lanes
|
|
367
|
+
let lanes;
|
|
368
|
+
if (args.length === 1 && PRESETS[args[0]]) {
|
|
369
|
+
const preset = args[0];
|
|
370
|
+
console.log(`Removing preset: ${preset} (${PRESETS[preset].join(", ")})`);
|
|
371
|
+
lanes = PRESETS[preset];
|
|
372
|
+
} else {
|
|
373
|
+
const invalid = args.filter((l) => !LANES[l]);
|
|
374
|
+
if (invalid.length) {
|
|
375
|
+
console.error(`Unknown lane(s): ${invalid.join(", ")}`);
|
|
376
|
+
console.error(`Run 'weeve list' to see available lanes.`);
|
|
377
|
+
process.exit(1);
|
|
378
|
+
}
|
|
379
|
+
lanes = args;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
console.log(`\nRemoving ${lanes.length} lane(s)...\n`);
|
|
383
|
+
for (const lane of lanes) {
|
|
384
|
+
const repo = `${ORG}/weeve-${lane}`;
|
|
385
|
+
console.log(` - ${lane}`);
|
|
386
|
+
run(`npx skills remove ${repo}`);
|
|
387
|
+
}
|
|
388
|
+
console.log(`\nDone. Removed: ${lanes.join(", ")}\n`);
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
case "demo": {
|
|
393
|
+
const presetArg = args[0];
|
|
394
|
+
|
|
395
|
+
if (!presetArg) {
|
|
396
|
+
console.log("\nAvailable demos:\n");
|
|
397
|
+
const demoPreviews = {
|
|
398
|
+
core: "Prism — design token management SaaS (compass, layers-plus, ally, rubric, pilot)",
|
|
399
|
+
engineering: "Volta — internal developer platform (forge, helm, verify, guard, pilot)",
|
|
400
|
+
product: "Canvas — no-code form builder (compass, layers-plus, ally, rubric, felt, pilot)",
|
|
401
|
+
strategy: "Beacon — B2B analytics at a strategic inflection point (compass, layers-plus, maven, pilot)",
|
|
402
|
+
gtm: "Relay — outbound sales automation SaaS (compass, maven, pitch, pilot)",
|
|
403
|
+
};
|
|
404
|
+
const maxName = Math.max(...Object.keys(demoPreviews).map((k) => k.length));
|
|
405
|
+
for (const [name, desc] of Object.entries(demoPreviews)) {
|
|
406
|
+
console.log(` ${name.padEnd(maxName + 2)}${desc}`);
|
|
407
|
+
}
|
|
408
|
+
console.log("\nUsage: weeve demo <preset>\n");
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (!PRESETS[presetArg]) {
|
|
413
|
+
console.error(`Unknown preset: ${presetArg}`);
|
|
414
|
+
console.error("Run 'weeve demo' to see available demos.");
|
|
415
|
+
process.exit(1);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const demoSrc = path.join(__dirname, "..", "examples", presetArg, "demo");
|
|
419
|
+
|
|
420
|
+
if (!fs.existsSync(demoSrc)) {
|
|
421
|
+
console.error(`No demo found for preset: ${presetArg}`);
|
|
422
|
+
process.exit(1);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const cwd = process.cwd();
|
|
426
|
+
const weeveYaml = path.join(cwd, "weeve.yaml");
|
|
427
|
+
|
|
428
|
+
if (fs.existsSync(weeveYaml)) {
|
|
429
|
+
console.error(`weeve.yaml already exists in ${cwd}. Remove it first or run in an empty directory.`);
|
|
430
|
+
process.exit(1);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Recursively copy demo folder to cwd
|
|
434
|
+
function copyDir(src, dest) {
|
|
435
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
436
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
437
|
+
const srcPath = path.join(src, entry.name);
|
|
438
|
+
const destPath = path.join(dest, entry.name);
|
|
439
|
+
if (entry.isDirectory()) {
|
|
440
|
+
copyDir(srcPath, destPath);
|
|
441
|
+
} else {
|
|
442
|
+
fs.copyFileSync(srcPath, destPath);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
copyDir(demoSrc, cwd);
|
|
448
|
+
|
|
449
|
+
const demoNames = { core: "Prism", engineering: "Volta", product: "Canvas", strategy: "Beacon", gtm: "Relay" };
|
|
450
|
+
const demoName = demoNames[presetArg];
|
|
451
|
+
const firstLane = FIRST_STEP_ORDER.find((l) => PRESETS[presetArg].includes(l));
|
|
452
|
+
const firstCmd = firstLane && firstLane !== "pilot" ? `/${firstLane}-intro` : `/pilot-intro`;
|
|
453
|
+
|
|
454
|
+
console.log(`\nDemo ready: ${demoName} (${presetArg} preset)\n`);
|
|
455
|
+
console.log(` weeve.yaml project config (docs_root: ./docs)`);
|
|
456
|
+
console.log(` docs/shared/ weeve-project.md, weeve-guardrails.md, weeve-intake.md\n`);
|
|
457
|
+
console.log(`Next steps:`);
|
|
458
|
+
console.log(` 1. weeve add ${presetArg} — install the lanes`);
|
|
459
|
+
console.log(` 2. ${firstCmd} — start the first lane\n`);
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
case "project": {
|
|
464
|
+
const subcmd = args[0];
|
|
465
|
+
|
|
466
|
+
if (!subcmd || subcmd === "show") {
|
|
467
|
+
// Walk up from cwd to find weeve.yaml
|
|
468
|
+
let dir = process.cwd();
|
|
469
|
+
let found = null;
|
|
470
|
+
for (let i = 0; i < 4; i++) {
|
|
471
|
+
const candidate = path.join(dir, "weeve.yaml");
|
|
472
|
+
if (fs.existsSync(candidate)) {
|
|
473
|
+
found = candidate;
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
const parent = path.dirname(dir);
|
|
477
|
+
if (parent === dir) break;
|
|
478
|
+
dir = parent;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (!found) {
|
|
482
|
+
console.log("\nNo weeve.yaml found in this directory or its parents.");
|
|
483
|
+
console.log("Run 'weeve init [preset]' to create one.\n");
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const raw = fs.readFileSync(found, "utf8");
|
|
488
|
+
console.log(`\nProject config: ${found}\n`);
|
|
489
|
+
|
|
490
|
+
// Parse and display key fields
|
|
491
|
+
const nameMatch = raw.match(/^\s{2}name:\s*(.+)$/m);
|
|
492
|
+
const tagMatch = raw.match(/^\s{2}tag:\s*(.+)$/m);
|
|
493
|
+
const docsMatch = raw.match(/^\s{2}docs_root:\s*(.+)$/m);
|
|
494
|
+
const schemaMatch = raw.match(/^schema_version:\s*(.+)$/m);
|
|
495
|
+
|
|
496
|
+
const name = nameMatch ? nameMatch[1].trim() : "(not set)";
|
|
497
|
+
const tag = tagMatch ? tagMatch[1].trim() : "(not set)";
|
|
498
|
+
const docsRoot = docsMatch ? docsMatch[1].trim() : `<vault>/Projects/${tag}/docs (via Claudette)`;
|
|
499
|
+
const schema = schemaMatch ? schemaMatch[1].trim() : "(not set)";
|
|
500
|
+
|
|
501
|
+
const maxLabel = 14;
|
|
502
|
+
console.log(` ${"name".padEnd(maxLabel)}${name}`);
|
|
503
|
+
console.log(` ${"tag".padEnd(maxLabel)}${tag}`);
|
|
504
|
+
console.log(` ${"docs_root".padEnd(maxLabel)}${docsRoot}`);
|
|
505
|
+
console.log(` ${"schema_version".padEnd(maxLabel)}${schema}`);
|
|
506
|
+
|
|
507
|
+
// Check for repos
|
|
508
|
+
const reposBlock = raw.match(/^\s{2}repos:\n((?:\s{4}.+\n?)*)/m);
|
|
509
|
+
if (reposBlock) {
|
|
510
|
+
console.log(` ${"repos".padEnd(maxLabel)}${reposBlock[1].trim().split("\n").length} registered`);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Check for depends_on
|
|
514
|
+
const depsBlock = raw.match(/^\s{2}depends_on:\n((?:\s{4}.+\n?)*)/m);
|
|
515
|
+
if (depsBlock) {
|
|
516
|
+
const depTags = [...depsBlock[1].matchAll(/tag:\s*(\S+)/g)].map((m) => m[1]);
|
|
517
|
+
const depNames = [...depsBlock[1].matchAll(/name:\s*(.+)/g)].map((m) => m[1].trim());
|
|
518
|
+
const depList = depTags.map((tag, i) => depNames[i] ? `${depNames[i]} (${tag})` : tag).join(", ");
|
|
519
|
+
console.log(` ${"depends_on".padEnd(maxLabel)}${depList}`);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Check for shared docs
|
|
523
|
+
const sharedDir = path.join(path.dirname(found), "docs", "shared");
|
|
524
|
+
if (fs.existsSync(sharedDir)) {
|
|
525
|
+
const sharedFiles = fs.readdirSync(sharedDir).filter((f) => f.endsWith(".md"));
|
|
526
|
+
console.log(` ${"shared/".padEnd(maxLabel)}${sharedFiles.join(", ")}`);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
console.log();
|
|
530
|
+
break;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
console.error(`Unknown project subcommand: ${subcmd}`);
|
|
534
|
+
console.error("Usage: weeve project show");
|
|
535
|
+
process.exit(1);
|
|
536
|
+
}
|
|
537
|
+
|
|
98
538
|
case "list":
|
|
99
539
|
case "lanes": {
|
|
100
540
|
console.log("\nAvailable lanes:\n");
|
|
@@ -127,11 +567,17 @@ switch (cmd) {
|
|
|
127
567
|
╚███╔███╔╝███████╗███████╗ ╚████╔╝ ███████╗
|
|
128
568
|
╚══╝╚══╝ ╚══════╝╚══════╝ ╚═══╝ ╚══════╝
|
|
129
569
|
|
|
130
|
-
Cross-functional
|
|
570
|
+
Cross-functional contract framework
|
|
131
571
|
|
|
132
572
|
Commands:
|
|
133
573
|
weeve add <lane> [lane2...] Install one or more lanes
|
|
134
574
|
weeve add <preset> Install a preset group of lanes
|
|
575
|
+
weeve remove <lane> [lane2…] Remove one or more lanes
|
|
576
|
+
weeve remove <preset> Remove a preset group of lanes
|
|
577
|
+
weeve init [preset] Scaffold weeve structure in current directory
|
|
578
|
+
weeve demo [preset] Copy a pre-built demo project to current directory
|
|
579
|
+
weeve project show Show current project config (weeve.yaml)
|
|
580
|
+
weeve status Show installed lanes and skill counts
|
|
135
581
|
weeve list Show all available lanes
|
|
136
582
|
weeve presets Show preset groups
|
|
137
583
|
|
|
@@ -139,6 +585,10 @@ Examples:
|
|
|
139
585
|
weeve add compass ally pilot Install three lanes
|
|
140
586
|
weeve add core Install core preset (compass, layers-plus, ally, rubric, pilot)
|
|
141
587
|
weeve add all Install everything
|
|
588
|
+
weeve init core Scaffold folder structure for the core preset
|
|
589
|
+
weeve demo core Copy the Prism demo project (ready to run immediately)
|
|
590
|
+
weeve status See which lanes are installed
|
|
591
|
+
weeve remove ally Remove a single lane
|
|
142
592
|
|
|
143
593
|
Presets:
|
|
144
594
|
all Every lane
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Weeve lane ownership
|
|
2
|
+
# Copy to .github/CODEOWNERS and replace team handles with your org's teams
|
|
3
|
+
# Requires GitHub branch protection with "Require review from Code Owners" enabled
|
|
4
|
+
|
|
5
|
+
weeve/compass/ @leadership
|
|
6
|
+
weeve/layers-plus/ @product
|
|
7
|
+
weeve/ally/ @design
|
|
8
|
+
weeve/rubric/ @design
|
|
9
|
+
weeve/pilot/ @leadership
|