create-quiver 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +289 -335
  2. package/README_FOR_AI.md +57 -44
  3. package/docs/AI_ONBOARDING_PROMPT.md.template +13 -3
  4. package/docs/COMMANDS.md.template +24 -0
  5. package/docs/GITFLOW_PR_GUIDE.md.template +11 -0
  6. package/docs/STANDARD.md.template +1 -1
  7. package/docs/SUPPORT_MATRIX.md.template +4 -0
  8. package/docs/TROUBLESHOOTING.md.template +29 -1
  9. package/docs/WORKFLOW.md.template +1 -1
  10. package/package.json +6 -1
  11. package/package.template.json +11 -6
  12. package/scripts/check-pr-readiness.sh +1 -1
  13. package/scripts/check-scope.sh +0 -1
  14. package/scripts/check-slice-readiness.sh +3 -4
  15. package/scripts/init-docs.sh +46 -6
  16. package/specs/quiver-v20-ai-cli-orchestration/EVIDENCE_REPORT.md +23 -0
  17. package/specs/quiver-v20-ai-cli-orchestration/EXECUTION_PLAN.md +57 -0
  18. package/specs/quiver-v20-ai-cli-orchestration/SPEC.md +202 -0
  19. package/specs/quiver-v20-ai-cli-orchestration/STATUS.md +35 -0
  20. package/specs/quiver-v20-ai-cli-orchestration/pr.md +100 -0
  21. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
  22. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
  23. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/slice.json +54 -0
  24. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/CLOSURE_BRIEF.md +39 -0
  25. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/EXECUTION_BRIEF.md +63 -0
  26. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/slice.json +55 -0
  27. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/CLOSURE_BRIEF.md +40 -0
  28. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/EXECUTION_BRIEF.md +60 -0
  29. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/slice.json +54 -0
  30. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/CLOSURE_BRIEF.md +43 -0
  31. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/EXECUTION_BRIEF.md +62 -0
  32. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/slice.json +62 -0
  33. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/CLOSURE_BRIEF.md +36 -0
  34. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/EXECUTION_BRIEF.md +63 -0
  35. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/slice.json +59 -0
  36. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/CLOSURE_BRIEF.md +32 -0
  37. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/EXECUTION_BRIEF.md +61 -0
  38. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/slice.json +59 -0
  39. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/CLOSURE_BRIEF.md +36 -0
  40. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/EXECUTION_BRIEF.md +64 -0
  41. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/slice.json +65 -0
  42. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/CLOSURE_BRIEF.md +36 -0
  43. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/EXECUTION_BRIEF.md +66 -0
  44. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/slice.json +63 -0
  45. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/CLOSURE_BRIEF.md +35 -0
  46. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/EXECUTION_BRIEF.md +64 -0
  47. package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/slice.json +77 -0
  48. package/specs/quiver-v21-ai-first-layout/EVIDENCE_REPORT.md +31 -0
  49. package/specs/quiver-v21-ai-first-layout/EXECUTION_PLAN.md +185 -0
  50. package/specs/quiver-v21-ai-first-layout/SPEC.md +212 -0
  51. package/specs/quiver-v21-ai-first-layout/STATUS.md +37 -0
  52. package/specs/quiver-v21-ai-first-layout/pr.md +110 -0
  53. package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
  54. package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +63 -0
  55. package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/slice.json +45 -0
  56. package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/CLOSURE_BRIEF.md +31 -0
  57. package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/EXECUTION_BRIEF.md +59 -0
  58. package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/slice.json +57 -0
  59. package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/CLOSURE_BRIEF.md +32 -0
  60. package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/EXECUTION_BRIEF.md +60 -0
  61. package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/slice.json +58 -0
  62. package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/CLOSURE_BRIEF.md +34 -0
  63. package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/EXECUTION_BRIEF.md +61 -0
  64. package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/slice.json +64 -0
  65. package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/CLOSURE_BRIEF.md +32 -0
  66. package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/EXECUTION_BRIEF.md +58 -0
  67. package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/slice.json +64 -0
  68. package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/CLOSURE_BRIEF.md +32 -0
  69. package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/EXECUTION_BRIEF.md +60 -0
  70. package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/slice.json +65 -0
  71. package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/CLOSURE_BRIEF.md +31 -0
  72. package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/EXECUTION_BRIEF.md +62 -0
  73. package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/slice.json +66 -0
  74. package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/CLOSURE_BRIEF.md +33 -0
  75. package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/EXECUTION_BRIEF.md +61 -0
  76. package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/slice.json +67 -0
  77. package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/CLOSURE_BRIEF.md +35 -0
  78. package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/EXECUTION_BRIEF.md +66 -0
  79. package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/slice.json +62 -0
  80. package/src/create-quiver/commands/ai.js +442 -0
  81. package/src/create-quiver/index.js +418 -81
  82. package/src/create-quiver/lib/ai/context-packs.js +158 -0
  83. package/src/create-quiver/lib/ai/execution-plan.js +254 -0
  84. package/src/create-quiver/lib/ai/executor.js +323 -0
  85. package/src/create-quiver/lib/ai/github.js +329 -0
  86. package/src/create-quiver/lib/ai/phase-gates.js +72 -0
  87. package/src/create-quiver/lib/ai/preflight.js +58 -0
  88. package/src/create-quiver/lib/ai/prompt-transport.js +81 -0
  89. package/src/create-quiver/lib/ai/prompts.js +39 -0
  90. package/src/create-quiver/lib/ai/providers.js +314 -0
  91. package/src/create-quiver/lib/ai/safety.js +151 -0
  92. package/src/create-quiver/lib/ai/spec-generator.js +314 -0
  93. package/src/create-quiver/lib/ai/spec-templates.js +715 -0
  94. package/src/create-quiver/lib/doctor.js +114 -0
  95. package/src/create-quiver/lib/git.js +21 -0
  96. package/src/create-quiver/lib/init-docs.js +277 -22
  97. package/src/create-quiver/lib/init-layout.js +426 -0
  98. package/src/create-quiver/lib/lifecycle.js +2 -2
  99. package/src/create-quiver/lib/paths.js +63 -2
  100. package/src/create-quiver/lib/project-scan.js +66 -0
  101. package/src/create-quiver/lib/readiness.js +4 -2
  102. package/src/create-quiver/lib/scope.js +125 -0
  103. package/src/create-quiver/lib/slice-graph.js +6 -0
  104. package/src/create-quiver/lib/slice.js +51 -8
  105. package/src/create-quiver/lib/state.js +18 -1
  106. package/src/create-quiver/lib/template-resolver.js +74 -0
@@ -1,7 +1,31 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const { readAllSlices } = require('./slice-graph');
4
+ const { hasGeneratedProjectSpec, hasInitializedStateMetadata, readState } = require('./state');
3
5
  const { worktreeList } = require('./git');
4
6
 
7
+ const NEW_LAYOUT_REQUIRED_PATHS = [
8
+ 'README.md',
9
+ 'AGENTS.md',
10
+ 'package.json',
11
+ 'docs/AI_CONTEXT.md',
12
+ 'docs/AI_ONBOARDING_PROMPT.md',
13
+ 'docs/COMMANDS.md',
14
+ 'docs/WORKFLOW.md',
15
+ '.quiver/state.json',
16
+ '.quiver/config.json',
17
+ '.quiver/.gitignore',
18
+ ];
19
+
20
+ const LEGACY_LAYOUT_PROBES = [
21
+ 'docs-template/',
22
+ 'tools/scripts/start-slice.sh',
23
+ 'tools/scripts/check-slice-readiness.sh',
24
+ 'tools/scripts/check-pr-readiness.sh',
25
+ '.github/pull_request_template.md',
26
+ 'docs/PROJECT_SCAN.json',
27
+ ];
28
+
5
29
  function readTextIfExists(filePath) {
6
30
  if (!fs.existsSync(filePath)) {
7
31
  return null;
@@ -30,6 +54,18 @@ function normalizeRelativePath(root, absolutePath) {
30
54
  return path.relative(root, absolutePath).split(path.sep).join('/');
31
55
  }
32
56
 
57
+ function hasPath(projectRoot, relativePath) {
58
+ return fs.existsSync(path.join(projectRoot, relativePath));
59
+ }
60
+
61
+ function collectPresentPaths(projectRoot, relativePaths) {
62
+ return relativePaths.filter((relativePath) => hasPath(projectRoot, relativePath));
63
+ }
64
+
65
+ function collectMissingPaths(projectRoot, relativePaths) {
66
+ return relativePaths.filter((relativePath) => !hasPath(projectRoot, relativePath));
67
+ }
68
+
33
69
  function collectAiMarkdownFiles(projectRoot) {
34
70
  const aiDir = path.join(projectRoot, 'docs', 'ai');
35
71
  if (!fs.existsSync(aiDir)) {
@@ -174,6 +210,82 @@ function countStackInfoLeaks(projectRoot) {
174
210
  return leaks;
175
211
  }
176
212
 
213
+ function collectLayoutReport(projectRoot) {
214
+ const hasStateMetadata = hasInitializedStateMetadata(readState(projectRoot));
215
+ const realSlices = readAllSlices(projectRoot);
216
+ const specSlugs = Array.from(new Set(realSlices.map((slice) => slice.specSlug))).sort((left, right) => left.localeCompare(right));
217
+ const newLayoutFiles = collectPresentPaths(projectRoot, NEW_LAYOUT_REQUIRED_PATHS);
218
+ const missingNewLayoutFiles = collectMissingPaths(projectRoot, NEW_LAYOUT_REQUIRED_PATHS);
219
+ const legacySignals = collectPresentPaths(projectRoot, LEGACY_LAYOUT_PROBES);
220
+ const hasLegacyProjectSpec = hasGeneratedProjectSpec(projectRoot);
221
+
222
+ if (hasLegacyProjectSpec) {
223
+ legacySignals.push('specs/<project-slug>/SPEC.md');
224
+ }
225
+
226
+ const hasNewLayout = missingNewLayoutFiles.length === 0;
227
+ const hasLegacyLayout = legacySignals.length > 0;
228
+
229
+ let layout = 'incomplete';
230
+ if (hasNewLayout && hasLegacyLayout) {
231
+ layout = 'hybrid';
232
+ } else if (hasNewLayout) {
233
+ layout = 'new';
234
+ } else if (hasLegacyLayout) {
235
+ layout = 'legacy';
236
+ }
237
+
238
+ const recommendations = [];
239
+
240
+ if (layout === 'new') {
241
+ if (specSlugs.length === 0) {
242
+ recommendations.push('No specs yet. That is valid after the AI-first init flow.');
243
+ } else {
244
+ recommendations.push(`Specs found: ${specSlugs.join(', ')}.`);
245
+ }
246
+
247
+ if (!hasPath(projectRoot, 'docs/PROJECT_MAP.md')) {
248
+ recommendations.push('Run `npx create-quiver analyze` to generate docs/PROJECT_MAP.md when you want the visible project map.');
249
+ }
250
+ } else if (layout === 'legacy') {
251
+ recommendations.push('Legacy layout detected. Run `npx create-quiver migrate` to add the modern .quiver/ contract and AI-first docs.');
252
+ } else if (layout === 'hybrid') {
253
+ recommendations.push('Hybrid layout detected. Keep the new .quiver/ contract as the source of truth and plan cleanup of legacy roots.');
254
+ recommendations.push('Review any remaining docs-template/, tools/scripts/, or docs/PROJECT_SCAN.json paths and migrate them only if they are still needed.');
255
+ } else {
256
+ recommendations.push('Incomplete layout detected. Restore the missing AI-first contract files before relying on this project for onboarding.');
257
+ if (missingNewLayoutFiles.length > 0) {
258
+ recommendations.push(`Missing files: ${missingNewLayoutFiles.join(', ')}.`);
259
+ }
260
+ if (!hasStateMetadata && !hasLegacyLayout) {
261
+ recommendations.push('Run `npx create-quiver --name "Project Name"` or `npx create-quiver init` to create the Quiver contract first.');
262
+ }
263
+ }
264
+
265
+ return {
266
+ hasLegacyLayout,
267
+ hasNewLayout,
268
+ hasStateMetadata,
269
+ layout,
270
+ legacySignals,
271
+ missingNewLayoutFiles,
272
+ newLayoutFiles,
273
+ recommendations,
274
+ realSlices,
275
+ specSlugs,
276
+ };
277
+ }
278
+
279
+ function collectDoctorReport(projectRoot) {
280
+ const layout = collectLayoutReport(projectRoot);
281
+ const warnings = collectDoctorWarnings(projectRoot);
282
+
283
+ return {
284
+ ...layout,
285
+ warnings,
286
+ };
287
+ }
288
+
177
289
  function collectDoctorWarnings(projectRoot) {
178
290
  const warnings = [];
179
291
 
@@ -208,5 +320,7 @@ function collectDoctorWarnings(projectRoot) {
208
320
  }
209
321
 
210
322
  module.exports = {
323
+ collectDoctorReport,
211
324
  collectDoctorWarnings,
325
+ collectLayoutReport,
212
326
  };
@@ -101,6 +101,23 @@ function statusPorcelain(repoRoot) {
101
101
  return tryGit(['status', '--porcelain'], repoRoot);
102
102
  }
103
103
 
104
+ function remoteList(repoRoot) {
105
+ const output = tryGit(['remote'], repoRoot);
106
+ return output ? output.split('\n').map((line) => line.trim()).filter(Boolean) : [];
107
+ }
108
+
109
+ function hasRemote(repoRoot, remoteName = 'origin') {
110
+ return remoteList(repoRoot).includes(remoteName);
111
+ }
112
+
113
+ function isCleanWorktree(repoRoot) {
114
+ return statusPorcelain(repoRoot) === '';
115
+ }
116
+
117
+ function isDetachedHead(repoRoot) {
118
+ return currentBranch(repoRoot) === '';
119
+ }
120
+
104
121
  function revListCount(repoRoot, range) {
105
122
  const output = tryGit(['rev-list', '--count', range], repoRoot);
106
123
  return Number(output || '0');
@@ -143,7 +160,11 @@ module.exports = {
143
160
  hasRemoteBranch,
144
161
  lsRemoteHeads,
145
162
  mergeBaseIsAncestor,
163
+ hasRemote,
164
+ isCleanWorktree,
165
+ isDetachedHead,
146
166
  revListCount,
167
+ remoteList,
147
168
  runGit,
148
169
  statusPorcelain,
149
170
  tryGit,
@@ -1,6 +1,12 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { execSync } = require('child_process');
4
+ const {
5
+ buildQuiverConfig,
6
+ buildQuiverInternalGitignore,
7
+ quiverInternalPaths,
8
+ resolveInitPackageScripts,
9
+ } = require('./init-layout');
4
10
  const { writeState } = require('./state');
5
11
 
6
12
  function ensureDir(dirPath) {
@@ -199,7 +205,7 @@ function writeFrontMatter(filePath, fields) {
199
205
  return nextContent;
200
206
  }
201
207
 
202
- function mergePackageJson(projectRoot, templateRoot, skipIfExists) {
208
+ function mergePackageJson(projectRoot, templateRoot, options = {}) {
203
209
  const packageTemplate = path.join(templateRoot, 'package.template.json');
204
210
  const packageJsonPath = path.join(projectRoot, 'package.json');
205
211
 
@@ -207,8 +213,13 @@ function mergePackageJson(projectRoot, templateRoot, skipIfExists) {
207
213
  return 'missing';
208
214
  }
209
215
 
216
+ const profile = options.profile || 'default';
217
+ const scripts = resolveInitPackageScripts(profile, { legacyScripts: options.legacyScripts === true });
218
+
210
219
  if (!fs.existsSync(packageJsonPath)) {
211
- fs.copyFileSync(packageTemplate, packageJsonPath);
220
+ const template = JSON.parse(fs.readFileSync(packageTemplate, 'utf8'));
221
+ template.scripts = scripts;
222
+ fs.writeFileSync(packageJsonPath, `${JSON.stringify(template, null, 2)}\n`);
212
223
  return 'created';
213
224
  }
214
225
 
@@ -217,14 +228,125 @@ function mergePackageJson(projectRoot, templateRoot, skipIfExists) {
217
228
 
218
229
  existing.scripts = {
219
230
  ...(existing.scripts || {}),
220
- ...(template.scripts || {}),
231
+ ...scripts,
221
232
  };
222
233
 
223
234
  fs.writeFileSync(packageJsonPath, `${JSON.stringify(existing, null, 2)}\n`);
224
- return skipIfExists ? 'merged' : 'updated';
235
+ return options.migrateMode ? 'merged' : 'updated';
225
236
  }
226
237
 
227
- function buildReadme(projectName, projectSlug) {
238
+ function buildReadme(projectName, projectSlug, profile = 'default') {
239
+ if (profile === 'minimal') {
240
+ return `# ${projectName}
241
+
242
+ [Descripción breve del proyecto]
243
+
244
+ ## Quick Start
245
+
246
+ Run Quiver from this project root. Do not install it globally.
247
+
248
+ \`\`\`bash
249
+ npm install
250
+ npx create-quiver analyze
251
+ npx create-quiver plan
252
+ npx create-quiver graph
253
+ npx create-quiver doctor
254
+ npx create-quiver next
255
+ \`\`\`
256
+
257
+ ## AI Workflow
258
+
259
+ Use \`AGENTS.md\` first, then \`docs/AI_CONTEXT.md\` and \`docs/AI_ONBOARDING_PROMPT.md\` for the working contract.
260
+
261
+ \`\`\`bash
262
+ npm run quiver:ai:onboard -- --dry-run
263
+ npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
264
+ npm run quiver:ai:plan -- --phase technical-plan --input acceptance-approved.md --dry-run
265
+ npm run quiver:ai:plan -- --phase spec --input technical-plan-approved.md --dry-run
266
+ \`\`\`
267
+
268
+ When a real spec exists, execute one approved slice at a time:
269
+
270
+ \`\`\`bash
271
+ npm run quiver:ai:execute-slice -- --slice specs/<spec-slug>/slices/<slice-id>/slice.json --dry-run
272
+ \`\`\`
273
+
274
+ ## Documentation
275
+
276
+ - [AI Context](./docs/AI_CONTEXT.md)
277
+ - [AI Onboarding Prompt](./docs/AI_ONBOARDING_PROMPT.md)
278
+ - [Commands](./docs/COMMANDS.md)
279
+ - [Workflow](./docs/WORKFLOW.md)
280
+ `;
281
+ }
282
+
283
+ if (profile !== 'full') {
284
+ return `# ${projectName}
285
+
286
+ [Descripción breve del proyecto]
287
+
288
+ ## Quick Start
289
+
290
+ Run Quiver from this project root. Do not install it globally.
291
+
292
+ \`\`\`bash
293
+ npm install
294
+ npx create-quiver analyze
295
+ npx create-quiver plan
296
+ npx create-quiver graph
297
+ npx create-quiver doctor
298
+ npx create-quiver next
299
+ \`\`\`
300
+
301
+ After \`analyze\`, use \`docs/PROJECT_MAP.md\` for the detected stack, package manager, and command surface.
302
+
303
+ ## AI-First Workflow
304
+
305
+ Quiver keeps the visible contract small: start with \`README.md\`, \`AGENTS.md\`, and \`docs/\`. Specs and slices should be created only after a real requirement and an approved technical plan.
306
+
307
+ Use dry-runs before spending model tokens:
308
+
309
+ \`\`\`bash
310
+ npm run quiver:ai:onboard -- --dry-run
311
+ npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
312
+ npm run quiver:ai:plan -- --phase technical-plan --input acceptance-approved.md --dry-run
313
+ npm run quiver:ai:plan -- --phase spec --input technical-plan-approved.md --dry-run
314
+ \`\`\`
315
+
316
+ When a real spec exists, execute one approved slice at a time:
317
+
318
+ \`\`\`bash
319
+ npm run quiver:ai:execute-slice -- --slice specs/<spec-slug>/slices/<slice-id>/slice.json --dry-run
320
+ \`\`\`
321
+
322
+ ## Project NPM Scripts
323
+
324
+ The generated project includes \`quiver:*\` npm scripts that call the Node CLI:
325
+
326
+ \`\`\`bash
327
+ npm run quiver:analyze
328
+ npm run quiver:plan
329
+ npm run quiver:graph
330
+ npm run quiver:next
331
+ npm run quiver:doctor
332
+ npm run quiver:ai:onboard -- --dry-run
333
+ npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
334
+ npm run quiver:ai:execute-slice -- --slice specs/<spec-slug>/slices/<slice-id>/slice.json --dry-run
335
+ \`\`\`
336
+
337
+ ## Documentation
338
+
339
+ - [Agents](./AGENTS.md)
340
+ - [AI Context](./docs/AI_CONTEXT.md)
341
+ - [AI Onboarding Prompt](./docs/AI_ONBOARDING_PROMPT.md)
342
+ - [Commands](./docs/COMMANDS.md)
343
+ - [Workflow](./docs/WORKFLOW.md)
344
+ - [GitFlow PR Guide](./docs/GITFLOW_PR_GUIDE.md)
345
+ - [Support Matrix](./docs/SUPPORT_MATRIX.md)
346
+ - [Troubleshooting](./docs/TROUBLESHOOTING.md)
347
+ `;
348
+ }
349
+
228
350
  return `# ${projectName}
229
351
 
230
352
  [Descripción breve del proyecto]
@@ -259,6 +381,23 @@ If you need to target another directory from outside the project, pass \`--dir\`
259
381
 
260
382
  After you run \`analyze\`, open \`docs/PROJECT_MAP.md\` for the detected stack, package manager, and command surface.
261
383
 
384
+ ## AI-First Workflow
385
+
386
+ Quiver is designed for an AI-first workflow: a planner agent reads the project context and prepares acceptance criteria, technical plans, specs, slices, and PR notes; executor agents then work one approved slice at a time with minimal context.
387
+
388
+ Start with dry-runs so you can inspect the provider, role, context pack, and invocation before spending model tokens:
389
+
390
+ \`\`\`bash
391
+ npm run quiver:ai:onboard -- --dry-run
392
+ npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
393
+ npm run quiver:ai:plan -- --phase technical-plan --input acceptance-approved.md --dry-run
394
+ npm run quiver:ai:plan -- --phase spec --input technical-plan-approved.md --dry-run
395
+ npm run quiver:ai:execute-slice -- --slice specs/${projectSlug}/slices/slice-01/slice.json --dry-run
396
+ npm run quiver:ai:pr -- --dry-run --ssh-host-alias github-work --identity-file ~/.ssh/github-work
397
+ \`\`\`
398
+
399
+ Remove \`--dry-run\` only after the phase output is approved and the local provider CLI is ready.
400
+
262
401
  ## Project NPM Scripts
263
402
 
264
403
  The generated project includes \`quiver:*\` npm scripts that call the Node CLI and are the preferred repeatable workflow:
@@ -269,6 +408,11 @@ npm run quiver:plan
269
408
  npm run quiver:graph
270
409
  npm run quiver:next
271
410
  npm run quiver:doctor
411
+ npm run quiver:ai:onboard -- --dry-run
412
+ npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
413
+ npm run quiver:ai:execute-slice -- --slice specs/${projectSlug}/slices/slice-01/slice.json --dry-run
414
+ npm run quiver:ai:doctor -- --dry-run --ssh-host-alias github-work --identity-file ~/.ssh/github-work
415
+ npm run quiver:ai:pr -- --dry-run --ssh-host-alias github-work --identity-file ~/.ssh/github-work
272
416
  npm run quiver:migrate
273
417
  npm run quiver:start-slice -- specs/${projectSlug}/slices/slice-01/slice.json
274
418
  npm run quiver:check-slice -- specs/${projectSlug}/slices/slice-01/slice.json
@@ -281,6 +425,7 @@ npm run quiver:refresh-active-slices
281
425
 
282
426
  The \`quiver:graph\` script prints the tree view by default; use \`npx create-quiver graph --format mermaid\` for PR-ready Markdown and \`--format dot\` when you want Graphviz source.
283
427
  The \`quiver:next\` script points to the next ready slice and can auto-start it behind a confirmation prompt.
428
+ The \`quiver:ai:*\` scripts standardize planner/executor AI flows. Use dry-run first: onboarding and planning dry-runs do not require provider auth, while \`quiver:ai:pr -- --dry-run\` validates \`gh\`, GitFlow docs, branch/worktree state, and SSH inputs without creating a PR.
284
429
  Use \`npx create-quiver next --all-ready\` when you want the full ready level instead of a single suggestion.
285
430
  The legacy Bash wrappers remain in \`tools/scripts/\` for compatibility, but new project-level automation should prefer the \`quiver:*\` scripts and the direct \`npx create-quiver ...\` commands below.
286
431
  \`npm run quiver:migrate\` is only for projects that were already initialized by Quiver.
@@ -311,7 +456,7 @@ Use \`{{GRAPH_COMMAND}} --format mermaid\` for GitHub-friendly graph embeds or \
311
456
  If the project never ran Quiver initialization before, do not use \`migrate\` as bootstrap. Run:
312
457
 
313
458
  \`\`\`bash
314
- npx create-quiver --name "Project Name"
459
+ npx create-quiver init --name "Project Name"
315
460
  \`\`\`
316
461
 
317
462
  If your team prefers a pinned local dependency, update the package first and then run the same flow:
@@ -339,6 +484,8 @@ Lee \`docs/AI_ONBOARDING_PROMPT.md\` y ejecútalo como fuente principal de verda
339
484
 
340
485
  Actúa como asistente de onboarding de IA. Prepara el contexto del proyecto para trabajar de forma segura con el workflow documentado, specs y slices.
341
486
 
487
+ Usa el rol planner para onboarding, criterios de aceptación, plan técnico y generación de specs/slices. Usa el rol executor solo cuando exista un slice aprobado y debas ejecutar su handoff con contexto mínimo.
488
+
342
489
  No modifiques código de producto salvo autorización explícita. Puedes crear o actualizar documentación de contexto si el onboarding lo requiere.
343
490
 
344
491
  Usa solo la documentación del repositorio como fuente de verdad. Si encuentras información faltante, ambigua o contradictoria, documenta el supuesto, el riesgo y continúa por el camino más seguro.
@@ -355,6 +502,8 @@ Record durable decisions in \`docs/DECISIONS.md\` so future AI agents do not re-
355
502
 
356
503
  ## First Slice Workflow
357
504
 
505
+ Use this section only for projects generated with the full compatibility layout. In the default AI-first layout, create real specs and slices with \`npx create-quiver ai plan --phase spec\` after acceptance criteria and the technical plan are approved.
506
+
358
507
  1. Review or refine specs/${projectSlug}/SPEC.md.
359
508
  2. Create the first slice from specs/${projectSlug}/slices/slice-template/slice.json.
360
509
  3. Review the plan with \`{{PLAN_COMMAND}}\` or \`npm run quiver:plan\`.
@@ -397,10 +546,15 @@ function initializeProjectDocs(options) {
397
546
  projectRoot,
398
547
  projectName,
399
548
  cliVersion,
549
+ includeTemplates = false,
550
+ legacyScripts = false,
400
551
  migrateMode = false,
552
+ profile = 'default',
553
+ templateRoot: providedTemplateRoot = '',
401
554
  } = options;
402
555
 
403
- const templateRoot = path.join(projectRoot, 'docs-template');
556
+ const templateRoot = providedTemplateRoot || path.join(projectRoot, 'docs-template');
557
+ const internalPaths = quiverInternalPaths(projectRoot);
404
558
  const replacements = {
405
559
  projectName,
406
560
  projectSlug: toProjectSlug(projectName),
@@ -413,17 +567,48 @@ function initializeProjectDocs(options) {
413
567
  const dirs = [
414
568
  'docs',
415
569
  'docs/ai',
416
- 'docs/tools',
417
- 'docs/archive',
418
- `specs/${replacements.projectSlug}/slices/slice-template`,
419
- 'tools/scripts',
570
+ '.quiver',
571
+ '.quiver/scans',
420
572
  ];
421
573
 
574
+ if (profile === 'full') {
575
+ dirs.push(
576
+ 'docs/archive',
577
+ 'docs/examples',
578
+ 'docs/tools',
579
+ `specs/${replacements.projectSlug}/slices/slice-template`,
580
+ 'tools/scripts',
581
+ );
582
+ } else if (legacyScripts) {
583
+ dirs.push('tools/scripts');
584
+ }
585
+
422
586
  for (const dir of dirs) {
423
587
  ensureDir(path.join(projectRoot, dir));
424
588
  }
425
589
 
426
590
  const operations = [];
591
+ if (!fs.existsSync(internalPaths.configPath)) {
592
+ fs.writeFileSync(internalPaths.configPath, `${JSON.stringify(buildQuiverConfig(), null, 2)}\n`);
593
+ operations.push({ source: 'Quiver config', destination: '.quiver/config.json', result: 'created' });
594
+ } else {
595
+ operations.push({ source: 'Quiver config', destination: '.quiver/config.json', result: 'skipped' });
596
+ }
597
+
598
+ fs.writeFileSync(internalPaths.gitignorePath, buildQuiverInternalGitignore());
599
+ operations.push({ source: 'Quiver internal gitignore', destination: '.quiver/.gitignore', result: 'updated' });
600
+
601
+ if (includeTemplates) {
602
+ fs.mkdirSync(internalPaths.templatesDir, { recursive: true });
603
+ fs.cpSync(templateRoot, internalPaths.templatesDir, {
604
+ recursive: true,
605
+ force: false,
606
+ errorOnExist: false,
607
+ preserveTimestamps: true,
608
+ });
609
+ operations.push({ source: 'packaged templates', destination: '.quiver/templates', result: 'merged' });
610
+ }
611
+
427
612
  const agentsSourcePath = path.join(templateRoot, 'AGENTS.md.template');
428
613
  if (fs.existsSync(agentsSourcePath)) {
429
614
  const agentsDestinationPath = path.join(projectRoot, 'AGENTS.md');
@@ -463,13 +648,45 @@ function initializeProjectDocs(options) {
463
648
  ['specs/[project-name]/slices/pr.md.template', `specs/${replacements.projectSlug}/slices/slice-template/pr.md.template`],
464
649
  ];
465
650
 
651
+ const minimalTemplateDestinations = new Set([
652
+ 'docs/AI_CONTEXT.md',
653
+ 'docs/AI_ONBOARDING_PROMPT.md',
654
+ 'docs/COMMANDS.md',
655
+ 'docs/WORKFLOW.md',
656
+ ]);
657
+ const defaultTemplateDestinations = new Set([
658
+ ...minimalTemplateDestinations,
659
+ 'docs/CONTEXTO.md',
660
+ 'docs/DECISIONS.md',
661
+ 'docs/GITFLOW_PR_GUIDE.md',
662
+ 'docs/INDEX.md',
663
+ 'docs/STATUS.md',
664
+ 'docs/SUPPORT_MATRIX.md',
665
+ 'docs/TESTING_GUIDE_FOR_AI.md',
666
+ 'docs/TROUBLESHOOTING.md',
667
+ 'docs/ai/LESSONS.md',
668
+ ]);
669
+
466
670
  for (const [source, destination, frontMatterFactory] of templateCopies) {
671
+ if (profile === 'minimal' && !minimalTemplateDestinations.has(destination)) {
672
+ continue;
673
+ }
674
+
675
+ if (profile === 'default' && !defaultTemplateDestinations.has(destination)) {
676
+ continue;
677
+ }
678
+
467
679
  const sourcePath = path.join(templateRoot, source);
468
680
  if (!fs.existsSync(sourcePath)) {
469
681
  continue;
470
682
  }
471
683
 
472
684
  const destinationPath = path.join(projectRoot, destination);
685
+ if (!migrateMode && fs.existsSync(destinationPath)) {
686
+ operations.push({ source, destination, result: 'skipped' });
687
+ continue;
688
+ }
689
+
473
690
  const result = copyRenderedFile(sourcePath, destinationPath, replacements, migrateMode, frontMatterFactory);
474
691
  operations.push({ source, destination, result });
475
692
  }
@@ -497,31 +714,58 @@ function initializeProjectDocs(options) {
497
714
  ['scripts/migrate-project.sh', 'tools/scripts/migrate-project.sh'],
498
715
  ];
499
716
 
717
+ const alwaysBinaryDestinations = new Set([
718
+ 'docs/ai/RULES.yaml',
719
+ ]);
720
+ const legacyScriptDestinations = new Set([
721
+ 'tools/scripts/start-slice.sh',
722
+ 'tools/scripts/refresh-active-slices.sh',
723
+ 'tools/scripts/check-slice-readiness.sh',
724
+ 'tools/scripts/check-pr-readiness.sh',
725
+ 'tools/scripts/cleanup-slice.sh',
726
+ 'tools/scripts/check-scope.sh',
727
+ 'tools/scripts/migrate-project.sh',
728
+ ]);
729
+
500
730
  for (const [source, destination] of binaryCopies) {
731
+ if (
732
+ profile !== 'full'
733
+ && !alwaysBinaryDestinations.has(destination)
734
+ && !(legacyScripts && legacyScriptDestinations.has(destination))
735
+ ) {
736
+ continue;
737
+ }
738
+
501
739
  const sourcePath = path.join(templateRoot, source);
502
740
  const destinationPath = path.join(projectRoot, destination);
503
741
  if (!fs.existsSync(sourcePath)) {
504
742
  continue;
505
743
  }
506
744
 
507
- const result = copyIfSourceExists(sourcePath, destinationPath, migrateMode);
745
+ const result = copyIfSourceExists(sourcePath, destinationPath, true);
508
746
  operations.push({ source, destination, result });
509
747
  }
510
748
 
511
749
  const aiPrinciplesSource = path.join(templateRoot, 'docs/ai/PRINCIPLES.md');
512
750
  if (fs.existsSync(aiPrinciplesSource)) {
513
751
  const aiPrinciplesDestination = path.join(projectRoot, 'docs/ai/PRINCIPLES.md');
514
- const result = copyRenderedFile(
515
- aiPrinciplesSource,
516
- aiPrinciplesDestination,
517
- replacements,
518
- migrateMode,
519
- frontMatterFor('AI operating principles', 'all AI work'),
520
- );
752
+ const result = !migrateMode && fs.existsSync(aiPrinciplesDestination)
753
+ ? 'skipped'
754
+ : copyRenderedFile(
755
+ aiPrinciplesSource,
756
+ aiPrinciplesDestination,
757
+ replacements,
758
+ migrateMode,
759
+ frontMatterFor('AI operating principles', 'all AI work'),
760
+ );
521
761
  operations.push({ source: 'docs/ai/PRINCIPLES.md', destination: 'docs/ai/PRINCIPLES.md', result });
522
762
  }
523
763
 
524
- const packageResult = mergePackageJson(projectRoot, templateRoot, migrateMode);
764
+ const packageResult = mergePackageJson(projectRoot, templateRoot, {
765
+ legacyScripts,
766
+ migrateMode,
767
+ profile,
768
+ });
525
769
  operations.push({ source: 'package.template.json', destination: 'package.json', result: packageResult });
526
770
 
527
771
  const mergedPackageJsonPath = path.join(projectRoot, 'package.json');
@@ -560,12 +804,21 @@ function initializeProjectDocs(options) {
560
804
  ];
561
805
 
562
806
  for (const [source, destination] of tierCopies) {
807
+ if (profile !== 'full') {
808
+ continue;
809
+ }
810
+
563
811
  const sourcePath = path.join(templateRoot, source);
564
812
  if (!fs.existsSync(sourcePath)) {
565
813
  continue;
566
814
  }
567
815
 
568
816
  const destinationPath = path.join(projectRoot, destination);
817
+ if (!migrateMode && fs.existsSync(destinationPath)) {
818
+ operations.push({ source, destination, result: 'skipped' });
819
+ continue;
820
+ }
821
+
569
822
  const result = copyRenderedFile(sourcePath, destinationPath, tierReplacements, migrateMode, ({
570
823
  body,
571
824
  }) => buildFrontMatterFields({
@@ -613,7 +866,9 @@ function initializeProjectDocs(options) {
613
866
  writeState(projectRoot, nextState);
614
867
 
615
868
  const searchPath = path.join(projectRoot, 'docs', 'SEARCH.md');
616
- if (!(migrateMode && fs.existsSync(searchPath))) {
869
+ if (profile !== 'full') {
870
+ operations.push({ source: 'docs/SEARCH.md', destination: 'docs/SEARCH.md', result: 'skipped-profile' });
871
+ } else if (!fs.existsSync(searchPath)) {
617
872
  const searchContent = `# Búsqueda por Tema
618
873
 
619
874
  **Última actualización:** ${replacements.currentDate}
@@ -662,7 +917,7 @@ function initializeProjectDocs(options) {
662
917
 
663
918
  const readmePath = path.join(projectRoot, 'README.md');
664
919
  if (!fs.existsSync(readmePath)) {
665
- fs.writeFileSync(readmePath, `${renderTemplate(buildReadme(projectName, replacements.projectSlug), replacements)}\n`);
920
+ fs.writeFileSync(readmePath, `${renderTemplate(buildReadme(projectName, replacements.projectSlug, profile), replacements)}\n`);
666
921
  operations.push({ source: 'README.md template', destination: 'README.md', result: 'created' });
667
922
  } else {
668
923
  operations.push({ source: 'README.md template', destination: 'README.md', result: 'skipped' });