@ulysses-ai/create-workspace 0.13.0-beta.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 (86) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +108 -0
  3. package/bin/create.mjs +79 -0
  4. package/lib/git.mjs +26 -0
  5. package/lib/init.mjs +129 -0
  6. package/lib/payload.mjs +44 -0
  7. package/lib/prompts.mjs +113 -0
  8. package/lib/scaffold.mjs +84 -0
  9. package/lib/upgrade.mjs +42 -0
  10. package/package.json +43 -0
  11. package/template/.claude/agents/aside-researcher.md +48 -0
  12. package/template/.claude/agents/implementer.md +39 -0
  13. package/template/.claude/agents/researcher.md +40 -0
  14. package/template/.claude/agents/reviewer.md +47 -0
  15. package/template/.claude/hooks/_utils.mjs +196 -0
  16. package/template/.claude/hooks/_utils.test.mjs +99 -0
  17. package/template/.claude/hooks/post-compact.mjs +7 -0
  18. package/template/.claude/hooks/pre-compact.mjs +34 -0
  19. package/template/.claude/hooks/repo-write-detection.mjs +107 -0
  20. package/template/.claude/hooks/session-end.mjs +91 -0
  21. package/template/.claude/hooks/session-start.mjs +150 -0
  22. package/template/.claude/hooks/subagent-start.mjs +44 -0
  23. package/template/.claude/hooks/workspace-update-check.mjs +42 -0
  24. package/template/.claude/hooks/worktree-create.mjs +53 -0
  25. package/template/.claude/lib/session-frontmatter.mjs +265 -0
  26. package/template/.claude/lib/session-frontmatter.test.mjs +242 -0
  27. package/template/.claude/recipes/migrate-from-notion.md +120 -0
  28. package/template/.claude/rules/agent-rules.md.skip +32 -0
  29. package/template/.claude/rules/cloud-infrastructure.md.skip +15 -0
  30. package/template/.claude/rules/coherent-revisions.md +24 -0
  31. package/template/.claude/rules/documentation.md.skip +13 -0
  32. package/template/.claude/rules/git-conventions.md +34 -0
  33. package/template/.claude/rules/honest-pushback.md +56 -0
  34. package/template/.claude/rules/local-dev-environment.md.skip +60 -0
  35. package/template/.claude/rules/memory-guidance.md +26 -0
  36. package/template/.claude/rules/product-integrity.md.skip +24 -0
  37. package/template/.claude/rules/scope-guard.md.skip +22 -0
  38. package/template/.claude/rules/superpowers-workflow.md.skip +22 -0
  39. package/template/.claude/rules/token-economics.md.skip +31 -0
  40. package/template/.claude/rules/work-item-tracking.md +90 -0
  41. package/template/.claude/rules/workspace-structure.md +69 -0
  42. package/template/.claude/scripts/add-repo-to-session.mjs +78 -0
  43. package/template/.claude/scripts/cleanup-work-session.mjs +108 -0
  44. package/template/.claude/scripts/create-work-session.mjs +124 -0
  45. package/template/.claude/scripts/migrate-open-work.mjs +91 -0
  46. package/template/.claude/scripts/migrate-session-layout.mjs +236 -0
  47. package/template/.claude/scripts/migrate-session-layout.test.mjs +144 -0
  48. package/template/.claude/scripts/trackers/github-issues.mjs +170 -0
  49. package/template/.claude/scripts/trackers/github-issues.test.mjs +190 -0
  50. package/template/.claude/scripts/trackers/interface.mjs +25 -0
  51. package/template/.claude/scripts/trackers/interface.test.mjs +40 -0
  52. package/template/.claude/settings.json +107 -0
  53. package/template/.claude/skills/aside/SKILL.md +125 -0
  54. package/template/.claude/skills/braindump/SKILL.md +96 -0
  55. package/template/.claude/skills/build-docs-site/SKILL.md +323 -0
  56. package/template/.claude/skills/build-docs-site/checklists/framing.md +221 -0
  57. package/template/.claude/skills/build-docs-site/checklists/pitfalls.md +228 -0
  58. package/template/.claude/skills/build-docs-site/checklists/review.md +130 -0
  59. package/template/.claude/skills/build-docs-site/scripts/bulk-fill-migration.py +393 -0
  60. package/template/.claude/skills/build-docs-site/scripts/forbidden-word-grep.mjs +159 -0
  61. package/template/.claude/skills/build-docs-site/scripts/leak-grep.mjs +328 -0
  62. package/template/.claude/skills/build-docs-site/templates/custom.css.tmpl +212 -0
  63. package/template/.claude/skills/build-docs-site/templates/docusaurus.config.ts.tmpl +95 -0
  64. package/template/.claude/skills/build-docs-site/templates/primitives/Arrow.tsx +87 -0
  65. package/template/.claude/skills/build-docs-site/templates/primitives/Box.tsx +90 -0
  66. package/template/.claude/skills/build-docs-site/templates/primitives/DiagramContainer.tsx +46 -0
  67. package/template/.claude/skills/build-docs-site/templates/primitives/Region.tsx +68 -0
  68. package/template/.claude/skills/build-docs-site/templates/primitives/SectionTitle.tsx +42 -0
  69. package/template/.claude/skills/build-docs-site/templates/primitives/tokens.ts +67 -0
  70. package/template/.claude/skills/build-docs-site/templates/sidebars.ts.tmpl +89 -0
  71. package/template/.claude/skills/build-docs-site/templates/spec.md.tmpl +119 -0
  72. package/template/.claude/skills/complete-work/SKILL.md +369 -0
  73. package/template/.claude/skills/handoff/SKILL.md +98 -0
  74. package/template/.claude/skills/maintenance/SKILL.md +116 -0
  75. package/template/.claude/skills/pause-work/SKILL.md +98 -0
  76. package/template/.claude/skills/promote/SKILL.md +77 -0
  77. package/template/.claude/skills/release/SKILL.md +126 -0
  78. package/template/.claude/skills/setup-tracker/SKILL.md +117 -0
  79. package/template/.claude/skills/start-work/SKILL.md +234 -0
  80. package/template/.claude/skills/sync-work/SKILL.md +73 -0
  81. package/template/.claude/skills/workspace-init/SKILL.md +420 -0
  82. package/template/.claude/skills/workspace-update/SKILL.md +108 -0
  83. package/template/.mcp.json +12 -0
  84. package/template/CLAUDE.md.tmpl +32 -0
  85. package/template/_gitignore +28 -0
  86. package/template/workspace.json.tmpl +15 -0
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import { colors, cls, layout, type StrokeClass } from './tokens';
3
+
4
+ export interface ArrowProps {
5
+ x1: number;
6
+ y1: number;
7
+ x2: number;
8
+ y2: number;
9
+ /**
10
+ * If true, the arrow bends at a right angle.
11
+ * The corner is placed based on `elbowAxis`:
12
+ * - 'horizontal-first': go horizontally to x2, then vertically to y2
13
+ * - 'vertical-first': go vertically to y2, then horizontally to x2
14
+ */
15
+ elbow?: boolean;
16
+ elbowAxis?: 'horizontal-first' | 'vertical-first';
17
+ strokeClass?: StrokeClass;
18
+ /** Override the marker fill. SVG markers can't be styled via parent CSS classes. */
19
+ markerColor?: string;
20
+ strokeWidth?: number;
21
+ dashed?: boolean;
22
+ /** Unique marker id suffix so multiple arrows can coexist with different colors. */
23
+ markerId?: string;
24
+ }
25
+
26
+ /**
27
+ * Note on arrowhead markers:
28
+ * SVG <marker> contents live in a shadow tree that does not inherit
29
+ * CSS classes from the host document. The marker fill must be a literal
30
+ * value. We default to the `text` color hex from tokens. If you need a
31
+ * theme-aware arrowhead, render two markers (one per theme) and switch
32
+ * via media query, or accept the cosmetic mismatch.
33
+ */
34
+ export function Arrow({
35
+ x1,
36
+ y1,
37
+ x2,
38
+ y2,
39
+ elbow = false,
40
+ elbowAxis = 'horizontal-first',
41
+ strokeClass = 'strokeStrong',
42
+ markerColor = colors.text,
43
+ strokeWidth = layout.arrowStrokeWidth,
44
+ dashed = false,
45
+ markerId = 'default',
46
+ }: ArrowProps) {
47
+ const id = `dx-arrowhead-${markerId}`;
48
+
49
+ let path: string;
50
+ if (elbow) {
51
+ if (elbowAxis === 'horizontal-first') {
52
+ path = `M ${x1} ${y1} L ${x2} ${y1} L ${x2} ${y2}`;
53
+ } else {
54
+ path = `M ${x1} ${y1} L ${x1} ${y2} L ${x2} ${y2}`;
55
+ }
56
+ } else {
57
+ path = `M ${x1} ${y1} L ${x2} ${y2}`;
58
+ }
59
+
60
+ return (
61
+ <g>
62
+ <defs>
63
+ <marker
64
+ id={id}
65
+ markerWidth={layout.arrowheadSize}
66
+ markerHeight={layout.arrowheadSize}
67
+ refX={layout.arrowheadSize - 1}
68
+ refY={layout.arrowheadSize / 2}
69
+ orient="auto-start-reverse"
70
+ >
71
+ <path
72
+ d={`M 0 0 L ${layout.arrowheadSize} ${layout.arrowheadSize / 2} L 0 ${layout.arrowheadSize} z`}
73
+ fill={markerColor}
74
+ />
75
+ </marker>
76
+ </defs>
77
+ <path
78
+ d={path}
79
+ fill="none"
80
+ className={cls.stroke[strokeClass]}
81
+ strokeWidth={strokeWidth}
82
+ strokeDasharray={dashed ? '4 3' : undefined}
83
+ markerEnd={`url(#${id})`}
84
+ />
85
+ </g>
86
+ );
87
+ }
@@ -0,0 +1,90 @@
1
+ import React from 'react';
2
+ import { cls, layout, type FillClass, type StrokeClass } from './tokens';
3
+
4
+ export type BoxVariant = 'default' | 'primary' | 'muted';
5
+
6
+ export interface BoxProps {
7
+ x: number;
8
+ y: number;
9
+ width: number;
10
+ height: number;
11
+ title?: string;
12
+ subtitle?: string;
13
+ variant?: BoxVariant;
14
+ fillClass?: FillClass;
15
+ strokeClass?: StrokeClass;
16
+ textClass?: FillClass;
17
+ rx?: number;
18
+ }
19
+
20
+ const variantMap: Record<BoxVariant, { fill: FillClass; stroke: StrokeClass; text: FillClass }> = {
21
+ default: { fill: 'surface', stroke: 'stroke', text: 'text' },
22
+ primary: { fill: 'primary', stroke: 'primary', text: 'surface' },
23
+ muted: { fill: 'surfaceStrong', stroke: 'stroke', text: 'textMuted' },
24
+ };
25
+
26
+ export function Box({
27
+ x,
28
+ y,
29
+ width,
30
+ height,
31
+ title,
32
+ subtitle,
33
+ variant = 'default',
34
+ fillClass,
35
+ strokeClass,
36
+ textClass,
37
+ rx = layout.boxRadius,
38
+ }: BoxProps) {
39
+ const v = variantMap[variant];
40
+ const fill = fillClass ?? v.fill;
41
+ const stroke = strokeClass ?? v.stroke;
42
+ const text = textClass ?? v.text;
43
+
44
+ const cx = x + width / 2;
45
+ const titleY = subtitle ? y + height / 2 - 4 : y + height / 2 + 4;
46
+ const subtitleY = y + height / 2 + 12;
47
+
48
+ return (
49
+ <g>
50
+ <rect
51
+ x={x}
52
+ y={y}
53
+ width={width}
54
+ height={height}
55
+ rx={rx}
56
+ ry={rx}
57
+ className={`${cls.fill[fill]} ${cls.stroke[stroke]}`}
58
+ strokeWidth={layout.boxStrokeWidth}
59
+ />
60
+ {title && (
61
+ <text
62
+ x={cx}
63
+ y={titleY}
64
+ textAnchor="middle"
65
+ dominantBaseline="middle"
66
+ fontSize={layout.titleFontSize}
67
+ fontFamily={layout.fontFamily}
68
+ fontWeight={600}
69
+ className={cls.fill[text]}
70
+ >
71
+ {title}
72
+ </text>
73
+ )}
74
+ {subtitle && (
75
+ <text
76
+ x={cx}
77
+ y={subtitleY}
78
+ textAnchor="middle"
79
+ dominantBaseline="middle"
80
+ fontSize={layout.subtitleFontSize}
81
+ fontFamily={layout.fontFamily}
82
+ className={cls.fill[text]}
83
+ opacity={0.75}
84
+ >
85
+ {subtitle}
86
+ </text>
87
+ )}
88
+ </g>
89
+ );
90
+ }
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+
3
+ export interface DiagramContainerProps {
4
+ /** SVG viewport width in pixels. */
5
+ width: number;
6
+ /** SVG viewport height in pixels. */
7
+ height: number;
8
+ /** Optional caption shown below the diagram. */
9
+ caption?: string;
10
+ /** Optional accessible label for the diagram. */
11
+ ariaLabel?: string;
12
+ children: React.ReactNode;
13
+ }
14
+
15
+ /**
16
+ * Outer wrapper for every diagram in the documentation site.
17
+ *
18
+ * Provides:
19
+ * - Consistent padding via the `dx-diagram-container` CSS class
20
+ * - Theme-aware background (light cream / dark surface) defined in custom.css
21
+ * - Caption rendering below the diagram
22
+ * - Accessible labelling
23
+ * - viewBox-based responsive sizing (the SVG scales to its container)
24
+ */
25
+ export function DiagramContainer({
26
+ width,
27
+ height,
28
+ caption,
29
+ ariaLabel,
30
+ children,
31
+ }: DiagramContainerProps) {
32
+ return (
33
+ <figure className="dx-diagram-container">
34
+ <svg
35
+ viewBox={`0 0 ${width} ${height}`}
36
+ xmlns="http://www.w3.org/2000/svg"
37
+ role="img"
38
+ aria-label={ariaLabel ?? caption ?? 'Diagram'}
39
+ preserveAspectRatio="xMidYMid meet"
40
+ >
41
+ {children}
42
+ </svg>
43
+ {caption && <figcaption className="dx-diagram-caption">{caption}</figcaption>}
44
+ </figure>
45
+ );
46
+ }
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import { cls, layout, type FillClass, type StrokeClass } from './tokens';
3
+
4
+ export interface RegionProps {
5
+ x: number;
6
+ y: number;
7
+ width: number;
8
+ height: number;
9
+ label?: string;
10
+ fillClass?: FillClass;
11
+ strokeClass?: StrokeClass;
12
+ labelClass?: FillClass;
13
+ dashed?: boolean;
14
+ rx?: number;
15
+ children?: React.ReactNode;
16
+ }
17
+
18
+ /**
19
+ * A grouped, labelled container that visually scopes a set of related
20
+ * elements. Use Region when you want to show "these things belong
21
+ * together" without committing to a Box-as-foreground meaning.
22
+ *
23
+ * The label sits above the top-left corner of the region.
24
+ * Children render inside the region's coordinate space.
25
+ */
26
+ export function Region({
27
+ x,
28
+ y,
29
+ width,
30
+ height,
31
+ label,
32
+ fillClass = 'surfaceStrong',
33
+ strokeClass = 'stroke',
34
+ labelClass = 'textMuted',
35
+ dashed = true,
36
+ rx = layout.boxRadius,
37
+ children,
38
+ }: RegionProps) {
39
+ return (
40
+ <g>
41
+ <rect
42
+ x={x}
43
+ y={y}
44
+ width={width}
45
+ height={height}
46
+ rx={rx}
47
+ ry={rx}
48
+ className={`${cls.fill[fillClass]} ${cls.stroke[strokeClass]}`}
49
+ strokeWidth={layout.boxStrokeWidth}
50
+ strokeDasharray={dashed ? '4 3' : undefined}
51
+ opacity={0.4}
52
+ />
53
+ {label && (
54
+ <text
55
+ x={x + 8}
56
+ y={y - 6}
57
+ fontSize={layout.captionFontSize}
58
+ fontFamily={layout.fontFamily}
59
+ fontWeight={600}
60
+ className={cls.fill[labelClass]}
61
+ >
62
+ {label}
63
+ </text>
64
+ )}
65
+ {children}
66
+ </g>
67
+ );
68
+ }
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { cls, layout, type FillClass } from './tokens';
3
+
4
+ export interface SectionTitleProps {
5
+ x: number;
6
+ y: number;
7
+ text: string;
8
+ textClass?: FillClass;
9
+ fontSize?: number;
10
+ align?: 'start' | 'middle' | 'end';
11
+ bold?: boolean;
12
+ }
13
+
14
+ /**
15
+ * A caption or section heading inside an SVG diagram.
16
+ * Use this for labels above a region or row, not for box titles
17
+ * (which are handled by Box's own title prop).
18
+ */
19
+ export function SectionTitle({
20
+ x,
21
+ y,
22
+ text,
23
+ textClass = 'text',
24
+ fontSize = layout.captionFontSize,
25
+ align = 'start',
26
+ bold = true,
27
+ }: SectionTitleProps) {
28
+ return (
29
+ <text
30
+ x={x}
31
+ y={y}
32
+ textAnchor={align}
33
+ dominantBaseline="middle"
34
+ fontSize={fontSize}
35
+ fontFamily={layout.fontFamily}
36
+ fontWeight={bold ? 600 : 400}
37
+ className={cls.fill[textClass]}
38
+ >
39
+ {text}
40
+ </text>
41
+ );
42
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Diagram tokens for the build-docs-site skill.
3
+ *
4
+ * Two exports:
5
+ * - `colors`: hex values, used where class-based styling can't reach
6
+ * (e.g., SVG <marker> contents in shadow tree).
7
+ * - `cls`: class name maps, used everywhere else. The matching CSS
8
+ * classes are defined in the site's custom.css.
9
+ *
10
+ * Why class names instead of CSS variables in fill/stroke attributes:
11
+ * Chromium's SVG paint pipeline does not reliably resolve
12
+ * `fill="var(--x)"` or `style={{fill: 'var(--x)'}}`. Class selectors
13
+ * with `fill: var(--x)` rules work consistently because the cascade
14
+ * resolves the variable before paint.
15
+ */
16
+
17
+ export const colors = {
18
+ // Semantic colors — light mode hex fallbacks.
19
+ // Kept in sync with --dx-* CSS variables in custom.css.
20
+ primary: '#3B6EA8',
21
+ accent: '#D97757',
22
+ surface: '#FFFFFF',
23
+ surfaceStrong: '#F2F2F2',
24
+ text: '#1A1A1A',
25
+ textMuted: '#666666',
26
+ stroke: '#CCCCCC',
27
+ strokeStrong: '#888888',
28
+ } as const;
29
+
30
+ export const cls = {
31
+ fill: {
32
+ primary: 'dx-fill-primary',
33
+ accent: 'dx-fill-accent',
34
+ surface: 'dx-fill-surface',
35
+ surfaceStrong: 'dx-fill-surface-strong',
36
+ text: 'dx-fill-text',
37
+ textMuted: 'dx-fill-text-muted',
38
+ stroke: 'dx-fill-stroke',
39
+ strokeStrong: 'dx-fill-stroke-strong',
40
+ },
41
+ stroke: {
42
+ primary: 'dx-stroke-primary',
43
+ accent: 'dx-stroke-accent',
44
+ surface: 'dx-stroke-surface',
45
+ surfaceStrong: 'dx-stroke-surface-strong',
46
+ text: 'dx-stroke-text',
47
+ textMuted: 'dx-stroke-text-muted',
48
+ stroke: 'dx-stroke-stroke',
49
+ strokeStrong: 'dx-stroke-stroke-strong',
50
+ },
51
+ } as const;
52
+
53
+ export type ColorToken = keyof typeof colors;
54
+ export type FillClass = keyof typeof cls.fill;
55
+ export type StrokeClass = keyof typeof cls.stroke;
56
+
57
+ // Layout constants shared across primitives.
58
+ export const layout = {
59
+ boxRadius: 6,
60
+ boxStrokeWidth: 1.5,
61
+ arrowStrokeWidth: 1.5,
62
+ arrowheadSize: 8,
63
+ titleFontSize: 14,
64
+ subtitleFontSize: 11,
65
+ captionFontSize: 12,
66
+ fontFamily: 'inherit',
67
+ } as const;
@@ -0,0 +1,89 @@
1
+ import type { SidebarsConfig } from '@docusaurus/plugin-content-docs';
2
+
3
+ /**
4
+ * Sidebar configuration for the documentation site.
5
+ *
6
+ * The build-docs-site skill replaces the placeholder structure below
7
+ * based on the user's Phase 1 answers (audience, structure, chapters).
8
+ *
9
+ * Patterns to know:
10
+ *
11
+ * 1. Clickable category labels — use `link: { type: 'doc', id: 'overview-doc-id' }`
12
+ * so clicking the category itself navigates to its overview page.
13
+ *
14
+ * 2. Generated category index — alternative when no overview doc exists:
15
+ * `link: { type: 'generated-index' }` auto-builds an index page from
16
+ * the category's children.
17
+ *
18
+ * 3. Nested categories — categories can contain other categories.
19
+ * Use sparingly; deep nesting hurts navigation.
20
+ *
21
+ * 4. Doc IDs — paths are relative to the docs/ directory, without
22
+ * the .md or .mdx extension.
23
+ *
24
+ * Replace the placeholder structure with the real chapter list during
25
+ * Phase 4 scaffold. The skill writes one entry per chapter from the spec.
26
+ */
27
+
28
+ const sidebars: SidebarsConfig = {
29
+ docs: [
30
+ 'index', // The site's root page (slug: /)
31
+
32
+ {
33
+ type: 'category',
34
+ label: 'Part I — Foundations',
35
+ link: {
36
+ type: 'doc',
37
+ id: 'part-1/overview',
38
+ },
39
+ items: [
40
+ 'part-1/chapter-1',
41
+ 'part-1/chapter-2',
42
+ 'part-1/chapter-3',
43
+ ],
44
+ },
45
+
46
+ {
47
+ type: 'category',
48
+ label: 'Part II — Systems',
49
+ link: {
50
+ type: 'doc',
51
+ id: 'part-2/overview',
52
+ },
53
+ items: [
54
+ 'part-2/chapter-4',
55
+ 'part-2/chapter-5',
56
+ // For long chapters, use nested categories with their own clickable label:
57
+ // {
58
+ // type: 'category',
59
+ // label: 'Chapter N — Title',
60
+ // link: { type: 'doc', id: 'part-2/chapter-n/overview' },
61
+ // items: ['part-2/chapter-n/topic-a', 'part-2/chapter-n/topic-b'],
62
+ // },
63
+ ],
64
+ },
65
+
66
+ {
67
+ type: 'category',
68
+ label: 'Part III — Integration',
69
+ link: {
70
+ type: 'doc',
71
+ id: 'part-3/overview',
72
+ },
73
+ items: [
74
+ 'part-3/chapter-final',
75
+ ],
76
+ },
77
+
78
+ {
79
+ type: 'category',
80
+ label: 'Appendices',
81
+ items: [
82
+ 'appendix/glossary',
83
+ 'appendix/tech-stack',
84
+ ],
85
+ },
86
+ ],
87
+ };
88
+
89
+ export default sidebars;
@@ -0,0 +1,119 @@
1
+ ---
2
+ state: ephemeral
3
+ lifecycle: active
4
+ type: design
5
+ topic: docs-site
6
+ author: {{USER}}
7
+ updated: {{DATE}}
8
+ ---
9
+
10
+ # Documentation Site Spec — {{PROJECT_NAME}}
11
+
12
+ Specification for the documentation site to be built by `/build-docs-site`. Generated from Phase 1 framing answers, Phase 2 source inventory, and review of the project's existing material.
13
+
14
+ ## Purpose
15
+
16
+ {{PURPOSE_PARAGRAPH}}
17
+
18
+ The site replaces the existing scattered documentation listed in the migration mapping below. Old material is treated as source content; the new site is the authoritative reference going forward.
19
+
20
+ ## Audience
21
+
22
+ **Primary:** {{AUDIENCE_PRIMARY}}
23
+
24
+ {{AUDIENCE_NOTES}}
25
+
26
+ The audience shapes tone, depth, and what counts as an implementation-detail leak (Phase 6 review).
27
+
28
+ ## Reading pattern
29
+
30
+ **Engagement style:** {{ENGAGEMENT_STYLE}}
31
+ **Content cohesion:** {{CONTENT_COHESION}}
32
+ **Chapter split threshold:** {{CHAPTER_SPLIT_THRESHOLD}} lines
33
+
34
+ These shape how chapters are sized and when long chapters get split into Docusaurus categories with sub-pages.
35
+
36
+ ## Structure
37
+
38
+ {{STRUCTURE_TYPE}}
39
+
40
+ ### Parts and chapters
41
+
42
+ {{CHAPTER_LIST}}
43
+
44
+ Each chapter has a one-paragraph synopsis. Chapter 1 is written last (technical-writing convention — the opener benefits from being written with full authority over what the rest says).
45
+
46
+ ## Existing documentation mapping
47
+
48
+ This table lists every existing doc that was identified in Phase 1 and what it maps to in the new site. The act of writing the new site IS the migration — these old files become source material and are replaced when the site is complete.
49
+
50
+ | Old file | Topic | Quality | New chapter | Status |
51
+ |----------|-------|---------|-------------|--------|
52
+ {{MAPPING_ROWS}}
53
+
54
+ Quality categories: `sparse` (thin or stub), `adequate` (covers the topic but could be better), `comprehensive` (good content, just disorganized), `outdated` (was good but is now wrong).
55
+
56
+ After Phase 6 coverage check passes, files marked as `replaced` are safe to delete.
57
+
58
+ ## Source inventory
59
+
60
+ Beyond the existing documentation, the following sources feed into the new site:
61
+
62
+ {{SOURCE_INVENTORY}}
63
+
64
+ ## Brand and style
65
+
66
+ **Identity source:** {{BRAND_SOURCE}}
67
+
68
+ **Colors:**
69
+ - Primary: {{BRAND_PRIMARY}}
70
+ - Accent: {{BRAND_ACCENT}}
71
+ - Background (light): {{BRAND_BACKGROUND}}
72
+ - Background (dark): {{BRAND_BACKGROUND_DARK}}
73
+
74
+ **Fonts:**
75
+ - Headings: {{BRAND_FONT_HEADING}}
76
+ - Body: {{BRAND_FONT_BODY}}
77
+ - Monospace: {{BRAND_FONT_MONO}}
78
+
79
+ **Voice and tone:**
80
+ {{BRAND_VOICE}}
81
+
82
+ ## Language constraints
83
+
84
+ Words, phrases, or framings to avoid throughout the documentation. The forbidden-word grep in Phase 6 uses this list.
85
+
86
+ {{LANGUAGE_CONSTRAINTS}}
87
+
88
+ ## Research treatment
89
+
90
+ **Research timing:** {{RESEARCH_TIMING}}
91
+ **Designed vs built:** {{DESIGNED_VS_BUILT}}
92
+
93
+ {{RESEARCH_NOTES}}
94
+
95
+ ## Diagrams plan
96
+
97
+ Initial diagram stubs by chapter. Fleshed out before Phase 7 (diagrams). Diagrams may be reused across chapters when they show the same concept.
98
+
99
+ {{DIAGRAM_STUBS}}
100
+
101
+ ## Implementation-detail rule
102
+
103
+ The documentation describes concepts and roles, not library choices. Library names, framework names, and model names appear only in the Tech Stack appendix unless the choice itself is architecturally meaningful.
104
+
105
+ The Phase 6 leak grep derives its detection list from the project's own dependency manifests (`package.json`, `pyproject.toml`, etc.) plus any project-specific terms added below.
106
+
107
+ **Project-specific terms to flag:**
108
+
109
+ {{PROJECT_LEAK_TERMS}}
110
+
111
+ ## Brainstorm-acronym translations
112
+
113
+ Terms that came from brainstorming sessions and need to be translated to descriptive names in the documentation. The descriptive name leads; the acronym (if useful) survives only as a parenthetical shorthand.
114
+
115
+ {{ACRONYM_TRANSLATIONS}}
116
+
117
+ ## Notes
118
+
119
+ This spec is consumed by `/complete-work` into release notes when the session finishes. Update it as decisions change during writing.