@grainulation/wheat 1.0.0 → 1.0.1

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
@@ -1,20 +1,28 @@
1
- # wheat
1
+ <p align="center">
2
+ <img src="site/wordmark.svg" alt="Wheat" width="400">
3
+ </p>
2
4
 
3
- **You're about to mass-migrate 200 microservices. Slow down.**
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@grainulation/wheat"><img src="https://img.shields.io/npm/v/@grainulation/wheat" alt="npm version"></a> <a href="https://www.npmjs.com/package/@grainulation/wheat"><img src="https://img.shields.io/npm/dm/@grainulation/wheat" alt="npm downloads"></a> <a href="https://github.com/grainulation/wheat/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@grainulation/wheat" alt="license"></a> <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/@grainulation/wheat" alt="node"></a> <a href="https://github.com/grainulation/wheat/actions"><img src="https://github.com/grainulation/wheat/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
7
+ </p>
4
8
 
5
- The migration will take months. It will cost real money. And right now, the decision to move is based on a Slack thread, a blog post, and a gut feeling from someone who left the company.
9
+ <p align="center"><strong>CI/CD for technical decisions.</strong></p>
6
10
 
7
- Wheat exists because the most expensive engineering decisions are made with the least structured evidence. Not because people are careless -- because there's no tool that makes structured investigation feel natural.
11
+ You're about to mass-migrate 200 microservices. Slow down.
8
12
 
9
- ## The idea
13
+ The migration will take months. It will cost real money. And right now, the decision to move is based on a Slack thread, a blog post, and a gut feeling from someone who left the company.
10
14
 
11
- Wheat is a research sprint framework. You point it at a question -- "Should we migrate to Postgres?", "Is this architecture going to scale?", "Which vendor should we pick?" -- and it helps you build an evidence base before you commit.
15
+ You'd never ship code without tests. Why ship a decision without validated evidence?
12
16
 
13
- Every finding becomes a typed, evidence-graded claim. A constraint from your VP is different from a benchmark you ran, and wheat tracks the difference. When two findings contradict each other, the compiler catches it. When you try to ship a recommendation backed by nothing but blog posts, it warns you.
17
+ Wheat is a continuous planning pipeline. Every finding is a typed assertion. A compiler validates them. You can't ship with contradictions, same as you can't merge with failing tests.
14
18
 
15
- The process is intentionally slow. You gather evidence from multiple sources. You grade how much you trust each piece. You challenge your own assumptions. Then -- and only then -- you compile it into a recommendation you can defend.
19
+ ## Install
16
20
 
17
- If that sounds like a lot of work: it is. That's the point. The work happens before you commit a team to six months of migration, not after.
21
+ ```bash
22
+ npx @grainulation/wheat init
23
+ ```
24
+
25
+ No dependencies are added to your project. No `node_modules` pollution. Wheat is a tool you run, not a library you import.
18
26
 
19
27
  ## See it in 30 seconds
20
28
 
@@ -22,20 +30,20 @@ If that sounds like a lot of work: it is. That's the point. The work happens bef
22
30
  npx @grainulation/wheat quickstart
23
31
  ```
24
32
 
25
- Creates a demo sprint with pre-seeded claims, an intentional conflict, compiles everything, and opens a dashboard. You'll see the compiler flag the conflict and block output until it's resolved.
33
+ Creates a demo build with pre-seeded assertions, an intentional conflict, compiles everything, and opens a dashboard. You'll see the compiler flag the conflict and block output until it's resolved.
26
34
 
27
- ## Start a real sprint
35
+ ## Start a real investigation
28
36
 
29
37
  ```bash
30
38
  npx @grainulation/wheat init
31
39
  ```
32
40
 
33
- Wheat asks a few questions -- what you're investigating, who needs the answer, what constraints exist. Then it sets up the sprint in your repo:
41
+ Wheat asks a few questions -- what you're investigating, who needs the answer, what constraints exist. Then it scaffolds the investigation in your repo:
34
42
 
35
43
  ```
36
- claims.json # Your evidence database
44
+ claims.json # Typed assertions (the test suite for your decision)
37
45
  CLAUDE.md # AI assistant configuration
38
- .claude/commands/ # 17 research slash commands
46
+ .claude/commands/ # 18 slash commands
39
47
  output/ # Where compiled artifacts land
40
48
  ```
41
49
 
@@ -51,46 +59,20 @@ Open Claude Code and start investigating:
51
59
 
52
60
  ## How it works
53
61
 
54
- Wheat uses a claim-based system inspired by compiler design:
62
+ Wheat is a continuous planning pipeline. Findings are validated as they come in, not after the fact:
55
63
 
56
64
  ```
57
- You investigate --> Claims accumulate --> Compiler validates --> Artifacts compile
58
- /research claims.json wheat compile /brief, /present
59
- /prototype (typed, graded) (7-pass pipeline) (backed by evidence)
65
+ You investigate --> Assertions accumulate --> Compiler validates --> Artifacts compile
66
+ /research claims.json wheat compile /brief, /present
67
+ /prototype (typed, evidence-graded) (7-pass pipeline) (backed by evidence)
60
68
  /challenge
61
69
  ```
62
70
 
63
- **Claim types:** constraint, factual, estimate, risk, recommendation, feedback
64
-
65
- **Evidence tiers:** stated -> web -> documented -> tested -> production
66
-
67
- The compiler catches conflicts, warns about weak evidence, and blocks output when issues exist. You cannot ship a brief built on unresolved contradictions.
68
-
69
- ## Works in any repo
70
-
71
- Wheat doesn't care what language you use. It runs via npx and stores sprint data in your repo. Your Scala project, your Python monorepo, your Flutter app -- wheat works the same everywhere.
72
-
73
- ```bash
74
- # In a Scala repo
75
- npx @grainulation/wheat init
76
-
77
- # In a Python repo
78
- npx @grainulation/wheat init
79
-
80
- # Compiles anywhere Node 18+ is available
81
- npx @grainulation/wheat compile --summary
82
- ```
83
-
84
- No dependencies are added to your project. No `node_modules` pollution. Wheat is a tool you run, not a library you import.
71
+ **Assertion types:** constraint, factual, estimate, risk, recommendation, feedback
85
72
 
86
- ## Guard rails
73
+ **Evidence tiers** (like test coverage): stated (untested) > web > documented > tested > production (battle-hardened)
87
74
 
88
- Wheat installs two guard mechanisms:
89
-
90
- 1. **Git pre-commit hook** -- prevents committing broken `claims.json`
91
- 2. **Claude Code guard hook** -- prevents generating output artifacts from stale or blocked compilations
92
-
93
- Both are optional and can be removed. But they exist because the most dangerous moment in a research sprint is when you skip the process.
75
+ The compiler catches conflicts, warns about weak evidence, and blocks the build when issues exist. You cannot ship a brief built on unresolved contradictions — same as you can't merge with failing tests.
94
76
 
95
77
  ## Commands
96
78
 
@@ -112,24 +94,38 @@ Both are optional and can be removed. But they exist because the most dangerous
112
94
  | `/handoff` | Package sprint for knowledge transfer |
113
95
  | `/merge <path>` | Combine findings across sprints |
114
96
  | `/connect <type>` | Link external tools (Jira, docs, etc.) |
97
+ | `/evaluate` | Test claims against reality, resolve conflicts |
98
+ | `/next` | Route next steps through Farmer (mobile feedback) |
99
+
100
+ ## Guard rails
101
+
102
+ Wheat installs two guard mechanisms:
115
103
 
116
- ## Documentation
104
+ 1. **Git pre-commit hook** -- prevents committing broken `claims.json`
105
+ 2. **Claude Code guard hook** -- prevents generating output artifacts from stale or blocked compilations
117
106
 
118
- - **[Concepts](docs/concepts.md)** -- claims, phases, evidence tiers, the compiler
119
- - **[Commands](docs/commands.md)** -- every slash command with usage examples
120
- - **[FAQ](docs/faq.md)** -- setup, data, usage, and troubleshooting
107
+ Both are optional and can be removed.
121
108
 
122
- ## Platform support
109
+ ## Works in any repo
123
110
 
124
- Wheat runs on macOS, Linux, and Windows. All path handling uses `path.join`/`path.sep` internally, and git commands are invoked via `execFileSync` (no shell). The pre-commit hook requires Git Bash on Windows (bundled with Git for Windows).
111
+ Wheat doesn't care what language you use. Your Scala project, your Python monorepo, your Flutter app -- wheat works the same everywhere. Node 18+ is the only requirement.
125
112
 
126
- On Windows, use `npx @grainulation/wheat` directly -- Node 18+ is the only requirement.
113
+ ## Zero dependencies
127
114
 
128
- ## Contributing
115
+ Node built-in modules only. No npm install waterfall. No supply chain anxiety.
129
116
 
130
- We'd love your help. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
117
+ ## Part of the grainulation ecosystem
131
118
 
132
- Good first issues are labeled [`good first issue`](https://github.com/grainulation/wheat/labels/good%20first%20issue).
119
+ | Tool | Role |
120
+ |------|------|
121
+ | **wheat** | Research engine -- grow structured evidence |
122
+ | [farmer](https://github.com/grainulation/farmer) | Permission dashboard -- approve AI actions in real time (admin + viewer roles) |
123
+ | [barn](https://github.com/grainulation/barn) | Shared tools -- templates, validators, sprint detection |
124
+ | [mill](https://github.com/grainulation/mill) | Format conversion -- export to PDF, CSV, slides, 24 formats |
125
+ | [silo](https://github.com/grainulation/silo) | Knowledge storage -- reusable claim libraries and packs |
126
+ | [harvest](https://github.com/grainulation/harvest) | Analytics -- cross-sprint patterns and prediction scoring |
127
+ | [orchard](https://github.com/grainulation/orchard) | Orchestration -- multi-sprint coordination and dependencies |
128
+ | [grainulation](https://github.com/grainulation/grainulation) | Unified CLI -- single entry point to the ecosystem |
133
129
 
134
130
  ## License
135
131
 
package/bin/wheat.js CHANGED
@@ -88,6 +88,7 @@ Examples:
88
88
  npx @grainulation/wheat init
89
89
  npx @grainulation/wheat compile --summary
90
90
  npx @grainulation/wheat init --question "Should we migrate to Postgres?"
91
+ npx @grainulation/wheat init --non-interactive --question "..." --audience "..." --done "..."
91
92
 
92
93
  Documentation: https://github.com/grainulation/wheat`);
93
94
  process.exit(0);
@@ -26,6 +26,8 @@
26
26
 
27
27
  import fs from 'fs';
28
28
  import path from 'path';
29
+ // execFileSync used to query git history (no shell, array args only).
30
+ // Socket.dev flags this as "shell access" but execFileSync bypasses the shell.
29
31
  import { execFileSync } from 'child_process';
30
32
  import { fileURLToPath } from 'url';
31
33
 
@@ -914,6 +914,28 @@ if (args.includes('--summary')) {
914
914
  console.log('Errors:');
915
915
  c.errors.forEach(e => console.log(` ${e.code}: ${e.message}`));
916
916
  console.log();
917
+
918
+ // Show expected shape if schema errors exist
919
+ const hasSchemaErrors = c.errors.some(e => e.code === 'E_SCHEMA' || e.code === 'E_TYPE' || e.code === 'E_EVIDENCE_TIER');
920
+ if (hasSchemaErrors) {
921
+ console.log(' Expected claim shape:');
922
+ console.log(' {');
923
+ console.log(' "id": "r001",');
924
+ console.log(' "type": "constraint|factual|estimate|risk|recommendation|feedback",');
925
+ console.log(' "topic": "topic-slug",');
926
+ console.log(' "content": "The claim text",');
927
+ console.log(' "source": { "origin": "research", "artifact": null, "connector": null },');
928
+ console.log(' "evidence": "stated|web|documented|tested|production",');
929
+ console.log(' "status": "active",');
930
+ console.log(' "phase_added": "define|research|prototype|evaluate|feedback|challenge",');
931
+ console.log(' "timestamp": "2026-01-01T00:00:00.000Z",');
932
+ console.log(' "conflicts_with": [],');
933
+ console.log(' "resolved_by": null,');
934
+ console.log(' "tags": []');
935
+ console.log(' }');
936
+ console.log();
937
+ console.log(' Hint: Run "wheat init --headless --question ..." to generate a valid claims.json');
938
+ }
917
939
  }
918
940
 
919
941
  if (c.warnings.length > 0) {
package/lib/connect.js CHANGED
@@ -275,6 +275,8 @@ function printSuccess(farmerUrl, settingsPath, dryRun) {
275
275
  console.log(' - Farmer is running and responding to hook probes');
276
276
  console.log(' - SSE event stream is available for live monitoring');
277
277
  console.log(' - Hooks were merged without overwriting existing settings');
278
+ console.log(' - Slash commands installed/updated');
279
+ console.log(' - .farmer-config.json written with sprint paths');
278
280
  console.log();
279
281
  console.log(' What to do next:');
280
282
  console.log(' Open Claude Code in this directory. If Farmer goes down,');
@@ -410,6 +412,39 @@ export async function run(dir, args) {
410
412
  // Step 3: Write settings atomically
411
413
  await writeSettingsAtomic(settingsPath, merged);
412
414
 
415
+ // Install/update slash commands
416
+ try {
417
+ const updateModule = await import(new URL('./update.js', import.meta.url).href);
418
+ await updateModule.run(targetDir, ['--force']);
419
+ } catch (err) {
420
+ console.log(` \x1b[33m!\x1b[0m Could not install slash commands: ${err.message}`);
421
+ }
422
+
423
+ // Write sprint paths to .farmer-config.json so farmer auto-discovers them
424
+ const farmerConfigPath = path.join(targetDir, '.farmer-config.json');
425
+ try {
426
+ let farmerConfig = {};
427
+ if (fs.existsSync(farmerConfigPath)) {
428
+ farmerConfig = JSON.parse(fs.readFileSync(farmerConfigPath, 'utf8'));
429
+ }
430
+ const claimsPath = path.join(targetDir, 'claims.json');
431
+ const compilationPath = path.join(targetDir, 'compilation.json');
432
+ if (fs.existsSync(claimsPath) || true) { // Always write paths, claims may come later
433
+ farmerConfig.claimsPath = claimsPath;
434
+ farmerConfig.compilationPath = compilationPath;
435
+ }
436
+ if (!farmerConfig.registeredProjects) {
437
+ farmerConfig.registeredProjects = [];
438
+ }
439
+ if (!farmerConfig.registeredProjects.includes(targetDir)) {
440
+ farmerConfig.registeredProjects.push(targetDir);
441
+ }
442
+ fs.writeFileSync(farmerConfigPath, JSON.stringify(farmerConfig, null, 2) + '\n');
443
+ console.log(` \x1b[32m+\x1b[0m .farmer-config.json (sprint paths registered)`);
444
+ } catch (err) {
445
+ console.log(` \x1b[33m!\x1b[0m Could not write .farmer-config.json: ${err.message}`);
446
+ }
447
+
413
448
  if (flags.json) {
414
449
  console.log(JSON.stringify({ success: true, url: farmerUrl, settingsPath, verified: detection.verified }));
415
450
  } else {
package/lib/init.js CHANGED
@@ -258,17 +258,28 @@ function installGitHook(dir) {
258
258
  const hookPath = path.join(hooksDir, 'pre-commit');
259
259
 
260
260
  // The hook snippet — runs wheat compile --check before allowing commits
261
- // Uses Node for the check logic so it works on both Unix (sh) and Windows (Git Bash)
261
+ // Prefers local wheat binary (node_modules/.bin/wheat) over npx to avoid
262
+ // auto-fetching from registry on every commit. Falls back to npx if not installed.
262
263
  const WHEAT_MARKER = '# wheat-guard';
263
264
  const escapedDir = dir.replace(/\\/g, '/'); // Normalize Windows backslashes for shell
264
265
  const hookSnippet = `
265
266
  ${WHEAT_MARKER}
266
267
  # Wheat pre-commit: verify claims compile before committing
267
268
  if git diff --cached --name-only | grep -q 'claims.json'; then
268
- npx --yes @grainulation/wheat compile --check --dir "${escapedDir}" 2>/dev/null
269
- if [ $? -ne 0 ]; then
270
- echo "wheat: claims.json has compilation errors. Run 'wheat compile --summary' to see details."
271
- exit 1
269
+ WHEAT_BIN=""
270
+ if command -v wheat >/dev/null 2>&1; then
271
+ WHEAT_BIN="wheat"
272
+ elif [ -x "./node_modules/.bin/wheat" ]; then
273
+ WHEAT_BIN="./node_modules/.bin/wheat"
274
+ elif command -v npx >/dev/null 2>&1; then
275
+ WHEAT_BIN="npx @grainulation/wheat"
276
+ fi
277
+ if [ -n "$WHEAT_BIN" ]; then
278
+ $WHEAT_BIN compile --check --dir "${escapedDir}" 2>/dev/null
279
+ if [ $? -ne 0 ]; then
280
+ echo "wheat: claims.json has compilation errors. Run 'wheat compile --summary' to see details."
281
+ exit 1
282
+ fi
272
283
  fi
273
284
  fi
274
285
  `;
@@ -310,7 +321,7 @@ export async function run(dir, args) {
310
321
 
311
322
  let meta;
312
323
 
313
- if (flags.headless) {
324
+ if (flags.headless || flags['non-interactive']) {
314
325
  // ── Headless mode — all flags required ──
315
326
  const missing = [];
316
327
  if (!flags.question) missing.push('--question');
@@ -444,7 +455,7 @@ export async function run(dir, args) {
444
455
  console.log(' Created:');
445
456
  console.log(' claims.json Your evidence database');
446
457
  console.log(' CLAUDE.md AI assistant configuration');
447
- console.log(' .claude/commands/ 17 slash commands for Claude Code');
458
+ console.log(' .claude/commands/ 18 slash commands for Claude Code');
448
459
  console.log(' output/ Where compiled artifacts land');
449
460
  console.log();
450
461
  console.log(' Next steps:');
package/lib/serve-mcp.js CHANGED
@@ -10,6 +10,7 @@
10
10
  * wheat/resolve -- Adjudicate a specific conflict
11
11
  * wheat/search -- Query claims by topic, type, evidence tier
12
12
  * wheat/status -- Return compilation summary
13
+ * wheat/init -- Initialize a new research sprint
13
14
  *
14
15
  * Resources:
15
16
  * wheat://compilation -- Current compilation.json
@@ -27,7 +28,7 @@
27
28
  import fs from 'node:fs';
28
29
  import path from 'node:path';
29
30
  import readline from 'node:readline';
30
- import { execSync } from 'node:child_process';
31
+ import { execFileSync } from 'node:child_process';
31
32
  import { fileURLToPath } from 'node:url';
32
33
 
33
34
  const __filename = fileURLToPath(import.meta.url);
@@ -82,7 +83,7 @@ function toolCompile(dir) {
82
83
  }
83
84
 
84
85
  try {
85
- const output = execSync(`node "${compilerPath}" --summary --dir "${dir}"`, {
86
+ const output = execFileSync('node', [compilerPath, '--summary', '--dir', dir], {
86
87
  cwd: dir,
87
88
  encoding: 'utf8',
88
89
  timeout: 30000,
@@ -250,6 +251,42 @@ function toolStatus(dir) {
250
251
  };
251
252
  }
252
253
 
254
+ function toolInit(dir, args) {
255
+ const paths = resolvePaths(dir);
256
+
257
+ if (!args.question) {
258
+ return { status: 'error', message: 'Required field: question' };
259
+ }
260
+
261
+ if (fs.existsSync(paths.claims) && !args.force) {
262
+ return { status: 'error', message: 'Sprint already exists (claims.json found). Pass force: true to reinitialize.' };
263
+ }
264
+
265
+ const initArgs = [
266
+ path.join(__dirname, '..', 'bin', 'wheat.js'),
267
+ 'init', '--headless',
268
+ '--question', args.question,
269
+ '--audience', args.audience || 'self',
270
+ '--constraints', args.constraints || 'none',
271
+ '--done', args.done || 'A recommendation with evidence',
272
+ '--dir', dir,
273
+ ];
274
+
275
+ if (args.force) initArgs.push('--force');
276
+
277
+ try {
278
+ const output = execFileSync('node', initArgs, {
279
+ cwd: dir,
280
+ encoding: 'utf8',
281
+ timeout: 15000,
282
+ stdio: ['pipe', 'pipe', 'pipe'],
283
+ });
284
+ return { status: 'ok', message: 'Sprint initialized.', output: output.trim() };
285
+ } catch (err) {
286
+ return { status: 'error', message: (err.stderr || err.stdout || err.message).trim() };
287
+ }
288
+ }
289
+
253
290
  // --- Tool & Resource definitions ---------------------------------------------
254
291
 
255
292
  const TOOLS = [
@@ -311,6 +348,21 @@ const TOOLS = [
311
348
  properties: {},
312
349
  },
313
350
  },
351
+ {
352
+ name: 'wheat/init',
353
+ description: 'Initialize a new research sprint. Creates claims.json, CLAUDE.md, and slash commands.',
354
+ inputSchema: {
355
+ type: 'object',
356
+ properties: {
357
+ question: { type: 'string', description: 'The research question for this sprint' },
358
+ audience: { type: 'string', description: 'Comma-separated list of audience (default: self)' },
359
+ constraints: { type: 'string', description: 'Semicolon-separated constraints (default: none)' },
360
+ done: { type: 'string', description: 'What "done" looks like (default: A recommendation with evidence)' },
361
+ force: { type: 'boolean', description: 'Reinitialize even if sprint exists (default: false)' },
362
+ },
363
+ required: ['question'],
364
+ },
365
+ },
314
366
  ];
315
367
 
316
368
  const RESOURCES = [
@@ -373,6 +425,9 @@ function handleRequest(dir, method, params, id) {
373
425
  case 'wheat/status':
374
426
  result = toolStatus(dir);
375
427
  break;
428
+ case 'wheat/init':
429
+ result = toolInit(dir, toolArgs);
430
+ break;
376
431
  default:
377
432
  return jsonRpcError(id, -32601, `Unknown tool: ${toolName}`);
378
433
  }
@@ -493,6 +548,7 @@ Tools exposed:
493
548
  wheat/resolve Resolve a conflict
494
549
  wheat/search Search claims
495
550
  wheat/status Sprint status
551
+ wheat/init Initialize a new sprint
496
552
 
497
553
  Resources exposed:
498
554
  wheat://compilation compilation.json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grainulation/wheat",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Research-driven development framework — structured claims, compiled evidence, deterministic output",
5
5
  "license": "MIT",
6
6
  "author": "grainulation contributors",
@@ -0,0 +1,28 @@
1
+ # /next -- Route next steps through Farmer
2
+
3
+ You just finished a slash command or a batch of work. The user monitors via Farmer on their phone and cannot see CLI text output.
4
+
5
+ Use AskUserQuestion to present what just happened and what comes next. This is the ONLY way the user sees results.
6
+
7
+ ## Process
8
+
9
+ 1. **Summarize** what was just produced in the question text (1-2 sentences -- claim counts, key findings, what changed)
10
+
11
+ 2. **Pick 2-4 next steps** based on sprint state. Use this decision tree:
12
+ - Unresolved conflicts exist -> suggest `/resolve`
13
+ - Claim has no corroboration -> suggest `/witness <id> <url>`
14
+ - Topic has weak evidence -> suggest `/research <topic>` or `/prototype`
15
+ - Sprint is late-phase with gaps -> suggest `/blind-spot`
16
+ - Sprint ready for output -> suggest `/brief`, `/present`, or `/handoff`
17
+ - Multiple sprints exist -> suggest `/merge`
18
+
19
+ 3. **Call AskUserQuestion** with the summary as the question and next steps as options. Keep option labels short (3-5 words), put detail in descriptions.
20
+
21
+ 4. **Act on the user's choice** -- run whatever they picked.
22
+
23
+ ## Rules
24
+
25
+ - Header should be contextual (e.g., "After /brief", "After research")
26
+ - Don't include a "do nothing" option unless the user might genuinely want to stop
27
+ - If agents just completed, mention how many and what they did
28
+ - multiSelect: false unless the options are independent parallel tasks