gru-ai 0.3.0 → 0.3.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
@@ -11,18 +11,16 @@
11
11
 
12
12
  <p align="center">
13
13
  <a href="#what-is-gruai">What Is gruAI?</a> •
14
+ <a href="#quickstart">Quickstart</a> •
14
15
  <a href="#the-pipeline">The Pipeline</a> •
15
- <a href="#the-context-tree">Context Tree</a> •
16
- <a href="#why-is-the-output-better">Why It Works</a> •
17
16
  <a href="#your-team">Your Team</a> •
18
- <a href="#quickstart">Quickstart</a>
17
+ <a href="#why-is-the-output-better">Why It Works</a>
18
+ <a href="#the-context-tree">Context Tree</a>
19
19
  </p>
20
20
 
21
- <p align="center">
22
- <video src="docs/assets/demo.mp4" width="720" autoplay loop muted playsinline>
23
- <img src="docs/assets/game-office.png" alt="gruAI pixel-art office with agents working" width="720" />
24
- </video>
25
- </p>
21
+ <div align="center">
22
+ <video src="https://github.com/user-attachments/assets/8859bc1f-8a04-47ac-9f94-35b9c71741eb" width="720" controls></video>
23
+ </div>
26
24
 
27
25
  ---
28
26
 
@@ -36,131 +34,87 @@ The system is designed for **depth, not speed.** Agents accumulate institutional
36
34
 
37
35
  **You make decisions. Agents make software.** Every directive flows through a 15-step pipeline — triage, audit, brainstorm, plan, build, review, and ship — grounded in published research from Anthropic and OpenAI on what actually makes AI output reliable.
38
36
 
39
- **gruAI is right for you if:**
37
+ ---
38
+
39
+ ## Is gruAI Right for You?
40
40
 
41
- ✅ You want to give direction, not write prompts — and have agents that brainstorm, challenge your thinking, and get it right without a reprompt loop
42
- ✅ You want mandatory code review and mechanical verification, not optional "looks good to me"
43
- You want institutional memoryagents that learn from mistakes and carry lessons across every task
44
- ✅ You want a structured pipeline backed by context engineering research, not ad-hoc agent orchestration
45
- ✅ You coordinate specialized roles (CTO, COO, CPO, CMO, engineers) not generic "AI assistants"
41
+ - ✅ You're running 10+ terminals, juggling context, reprompting the same mistakes — and you want to hand down a directive and walk away
42
+ - ✅ You've been burned by agents that "review" their own code — you want reviews that are mandatory, mechanical, and impossible to skip
43
+ - Your agents forget everything between sessions you want a team that remembers what broke last time
44
+ - ✅ You're the bottleneck for every decision, every prompt, every context refresh — you want to be the CEO, not the project manager
45
+ - ✅ You like running a one-person company with a full AI team, and you want it to actually feel that way — not like managing a chatbot farm
46
+ - ✅ You want agents that push back on your ideas before building, not agents that say yes and ship the wrong thing
46
47
 
47
48
  ---
48
49
 
49
50
  ## The Pipeline
50
51
 
51
- You say *"add a payment system."* The pipeline takes it from here — 15 steps across 5 phases.
52
+ You type: `/directive Create a landing page for gruAI`. Here's what happens next.
52
53
 
53
- | Icon | Meaning |
54
- |:----:|---------|
55
- | :gear: | **System step** — automated, no agent or human involved |
56
- | :busts_in_silhouette: | **Agent step** — one or more AI agents do the work |
57
- | :diamond_shape_with_a_dot_inside: | **CEO gate** — pipeline pauses for your decision |
54
+ **1. Triage** *Automated*
58
55
 
59
- ### Phase 1: Intake
56
+ Classified **heavyweight** — touches copy, layout, SEO, and design across multiple files. Each agent gets [role-scoped context](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents): the CTO gets your tech stack and component patterns, the CMO gets your positioning docs, engineers get your existing layout system. Not a 200K-token dump. [Start simple, add complexity only when needed.](https://www.anthropic.com/research/building-effective-agents)
60
57
 
61
- | # | Step | Who | What Happens |
62
- |:-:|------|:---:|-------------|
63
- | 1 | :gear: **Triage** | System | Classifies your directive by weight: lightweight, medium, heavyweight, or strategic. *"Add a payment system"* spans API, database, and UI — classified **heavyweight**. [Start simple, add complexity only when needed.](https://www.anthropic.com/research/building-effective-agents) |
64
- | 2 | :gear: **Checkpoint** | System | Checks for prior progress. If a session died mid-execution, it reads `directive.json` and [resumes from the last completed step](https://www.anthropic.com/engineering/building-c-compiler) — no work is lost. |
65
- | 3 | :gear: **Read** | System | Parses your directive brief, creates structured metadata, and extracts your Definition of Done. |
58
+ **2. Audit** *QA Engineer CTO*
66
59
 
67
- ### Phase 2: Analysis
60
+ QA scans the codebase: finds the existing `/app` route structure, the Tailwind config, that there's no `og:image` setup, and that the current root page is a placeholder. CTO recommends: reuse the existing layout components, add Open Graph meta from the start, keep it server-rendered for SEO — no need for a SPA or a CMS.
68
61
 
69
- | # | Step | Who | What Happens |
70
- |:-:|------|:---:|-------------|
71
- | 4 | :gear: **Context** | System | Loads lessons, design docs, and intel — [scoped to what this directive needs](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents), not a 200K-token dump. |
72
- | 5 | :busts_in_silhouette: **Audit** | QA Engineer, then CTO | Two-agent sequential audit. QA scans the codebase (pure facts: which files, what state, what breaks). Then the CTO recommends approaches. Identifies existing API patterns, database schema, and security considerations. |
73
- | 6 | :busts_in_silhouette: **Brainstorm** | CTO + CPO + CMO | C-suite agents independently propose approaches, then [deliberate and argue](https://www.anthropic.com/engineering/multi-agent-research-system). CTO pushes for Stripe, CPO argues for simpler in-house billing, CMO flags pricing page implications. They surface 3 questions for you. |
62
+ **3. Debate** *CTO + CPO + CMO*
74
63
 
75
- ### Phase 3: Planning
64
+ **You're not in the room.** The C-suite agents independently propose approaches, then [argue](https://www.anthropic.com/engineering/multi-agent-research-system):
76
65
 
77
- | # | Step | Who | What Happens |
78
- |:-:|------|:---:|-------------|
79
- | 7 | :diamond_shape_with_a_dot_inside: **Clarification** | System **CEO confirms** | Synthesizes intent from your brief, audit findings, and brainstorm. Surfaces conflicts and gaps. **You answer the 3 questions** catching misalignment here costs one interaction instead of a full reopen. |
80
- | 8 | :busts_in_silhouette: **Plan** | COO | Decomposes the directive into projects, assigns agents and reviewers. Payment system → 2 projects: backend engineer builds API + database, frontend engineer builds UI. CTO reviews both. |
81
- | 9 | :diamond_shape_with_a_dot_inside: **Approve** | **CEO reviews plan** | **You review the plan** before any code is written. [Human review at trust boundaries only](https://www.anthropic.com/engineering/building-c-compiler) you gate the plan and the result, not every step in between. |
66
+ > **CTO:** *"Static HTML page. One task, no framework overhead. We don't need React for a landing page — it's marketing content, not an app."*
67
+ >
68
+ > **CPO:** *"A static page won't convert. Developers want to see the product work before they install anything. We need an interactive demo or at minimum an embedded video walkthrough."*
69
+ >
70
+ > **CMO:** *"Neither matters if nobody finds it. An SPA landing page is invisible to Google. Server-rendered with proper meta tags, structured data, and a clear CTA or we're building for an audience of zero."*
82
71
 
83
- ### Phase 4: Execution
72
+ They find common ground: server-rendered page with an embedded demo video. Then they surface 3 questions for you.
84
73
 
85
- | # | Step | Who | What Happens |
86
- |:-:|------|:---:|-------------|
87
- | 10 | :busts_in_silhouette: **Project Brainstorm** | CTO + assigned builder | Break each project into concrete tasks with Definition of Done criteria. API project gets 3 tasks: Stripe integration, webhook handling, subscription management. |
88
- | 11 | :gear: **Setup** | System | Creates a git branch to isolate changes. |
89
- | 12 | :busts_in_silhouette: **Execute** | Assigned builders + reviewers | Builders work through tasks. After each task, a [separate reviewer evaluates with fresh context](https://www.anthropic.com/research/building-effective-agents) — no builder reasoning, no confirmation bias. Failed review triggers a fix cycle. |
74
+ **4. Clarify** 👤 **You**
90
75
 
91
- ### Phase 5: Verification
76
+ You answer 3 questions: *"Should the demo be live or a video?"* → video for now. *"Target audience — developers or technical founders?"* → developers first. *"Ship under /landing or replace the root?"* → replace root, the current placeholder adds no value.
92
77
 
93
- | # | Step | Who | What Happens |
94
- |:-:|------|:---:|-------------|
95
- | 13 | :gear: **Review Gate** | System | Bash scripts — not LLMs — [mechanically verify](https://openai.com/index/harness-engineering/) that every task was reviewed by a different agent, every DOD criterion was evaluated, and review artifacts exist. |
96
- | 14 | :gear: **Wrapup** | System | Updates lessons and design docs. Generates a CEO digest with files changed, review results, and revert commands. [Knowledge persists](https://arxiv.org/abs/2602.20478) for future directives. |
97
- | 15 | :diamond_shape_with_a_dot_inside: **Completion** | **CEO** | **Mandatory for all weights.** You review the digest and decide: approve (ship it), amend (fix specific issues), or reopen (start over). The pipeline never ships without your sign-off. |
78
+ **5. Plan** *COO* 👤 **You**
98
79
 
99
- ### Weight Adaptation
80
+ COO breaks it into 2 projects with 6 tasks:
81
+ - **Project 1:** Full-stack engineer builds page structure — hero with tagline and demo video, feature grid with pipeline highlights, agent team section, and Open Graph meta. 4 tasks.
82
+ - **Project 2:** Frontend engineer builds responsive layout — mobile breakpoints, CTA positioning, and dark mode support. 2 tasks.
100
83
 
101
- | Weight | Example | Skips | CEO Gates |
102
- |--------|---------|-------|-----------|
103
- | **Lightweight** | Fix a typo | Brainstorm | Completion only |
104
- | **Medium** | Add dark mode toggle | Brainstorm | Completion only |
105
- | **Heavyweight** | New payment system | Nothing | Clarification + Approve + Completion |
106
- | **Strategic** | Platform migration | Nothing | Clarification + Approve + Completion |
84
+ CTO reviews both projects. Each task has a Definition of Done: *"Hero section renders demo video with fallback image, loads in under 2s on 3G."* **You approve the plan** before any code is written.
107
85
 
108
- ---
86
+ **6. Build** — *Engineers*
109
87
 
110
- ## The Context Tree
88
+ Full-stack engineer builds the hero section, feature grid, and OG meta on an isolated git branch. Each task runs in a [clean context window](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) — the agent building the hero section doesn't carry leftover context from the meta tags task. After each task, a [separate reviewer evaluates with fresh context](https://www.anthropic.com/research/building-effective-agents) — no builder reasoning, no confirmation bias.
111
89
 
112
- All state lives in `.context/` at your repo root plain markdown and JSON, version-controlled alongside your code.
90
+ **7. Review***Reviewers + Automated*
113
91
 
114
- ```
115
- .context/
116
- ├── directives/ # All work lives here
117
- │ └── dark-mode/
118
- │ ├── directive.json # Pipeline state, weight, progress
119
- │ ├── directive.md # CEO brief
120
- │ ├── audit.md # CTO's technical audit
121
- │ ├── brainstorm.md # C-suite deliberation
122
- │ └── projects/
123
- │ └── dark-mode/
124
- │ └── project.json # Tasks, DOD, agents, reviews
125
- ├── lessons/ # What went wrong (reactive)
126
- ├── design/ # Why the system works this way (proactive)
127
- ├── intel/ # External research from /scout
128
- └── reports/ # CEO digests
129
- ```
92
+ > **Round 1:** CTO reviews the hero section. Finds 3 issues: missing `<meta description>` tag (SEO blind spot), layout breaks below 375px on the feature grid (iPhone SE), and no `loading="lazy"` on the demo video (kills page speed score). Sends findings back to builder with specific file locations and expected fixes.
93
+ >
94
+ > **Round 2:** Builder fixes all three. CTO reviews again with fresh context — doesn't remember giving the feedback, evaluates the code on its own merit. Finds one remaining issue: `#aaa` text on `#fff` background in the feature section fails WCAG AA contrast (4.5:1 required, got 2.7:1). Builder bumps to `#595959`. **Passes.**
130
95
 
131
- **Directive Projects Tasks.** A directive is a unit of work ("add dark mode"). The COO decomposes it into projects, each with tasks, agents, reviewers, and a Definition of Done. `directive.json` tracks pipeline progress — any session can read it and resume where it left off. `project.json` is the source of truth for what needs building and whether it passed review.
96
+ Bash scripts [verify](https://openai.com/index/harness-engineering/) every task was reviewed by a different agent than the one that built it. No review can be skipped, faked, or self-certified. This [evaluator-optimizer loop](https://www.anthropic.com/research/building-effective-agents) runs up to 3 rounds per task.
132
97
 
133
- **Knowledge compounds.** Lessons, design rationale, and standing corrections persist across directives. Agents load relevant context just-in-time not everything, just what they need for their role and task. No database, no external service — just files.
98
+ **8. Ship***Automated*
134
99
 
135
- ---
136
-
137
- ## Why Is the Output Better?
138
-
139
- Every point below traces to published research from Anthropic and OpenAI. This isn't a workflow we invented — it's assembled from what the research says actually works.
140
-
141
- - **Agents brainstorm and argue before anyone writes code.** For strategic directives, your C-suite agents independently propose approaches, then deliberate — challenging assumptions, resolving disagreements, and surfacing questions for you. Anthropic's research found [multi-agent outperformed single-agent by 90.2%](https://www.anthropic.com/engineering/multi-agent-research-system). The pipeline implements their [orchestrator-workers pattern](https://www.anthropic.com/research/building-effective-agents) where specialized agents collaborate, producing better results than any single agent.
100
+ Lessons captured: *"Always add OG meta tags when creating new pages"* and *"Check WCAG contrast on all text colors."* Design docs updated with the new route structure. CEO digest generated with all 8 files changed, both review rounds summarized, and `git revert` commands ready if needed. [Knowledge persists](https://arxiv.org/abs/2602.20478) — next time someone creates a page, agents already know about the OG tags.
142
101
 
143
- - **Reviewers evaluate intent, not just code.** Each reviewer gets [fresh context](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) scoped to the task they never see the builder's reasoning, preventing confirmation bias. They verify against your Definition of Done (what you asked for), not just whether the code compiles. This is Anthropic's [evaluator-optimizer pattern](https://www.anthropic.com/research/building-effective-agents): one agent generates, another evaluates, issues get fixed in-loop — not after the fact.
144
-
145
- - **Context is isolated, not accumulated.** Each agent spawns with a [clean context window](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) scoped to exactly what it needs. No 200K-token sessions where the model forgets what it read at the start. Anthropic's context engineering research shows accuracy degrades as token count increases — gruAI treats context as a finite resource under active degradation.
102
+ **9. Your Call**👤 **You**
146
103
 
147
- - **Verification is mechanical.** Bash scripts not LLMs enforce pipeline integrity: schema validation, self-review prevention, step dependency checks, role assignment verification. This follows Anthropic's [poka-yoke principle](https://www.anthropic.com/research/building-effective-agents) (error-proof design) and OpenAI's finding that [invariants should be enforced through structural tests](https://openai.com/index/harness-engineering/), not judgment.
104
+ You see the digest: 8 files changed, 2 review rounds, all 6 DOD criteria met, zero open issues. You open the page in your browser, check mobile, and decide: **approve** it as-is, **amend** with specific fixes (*"bump the CTA font size"*), **extend** the directive with new scope (*"now add a pricing section"*), or **redirect** if the approach was wrong. The pipeline never ships without your sign-off and never limits you to just "accept" or "reject."
148
105
 
149
- - **The harness determines output quality, not model intelligence.** Anthropic found that ["the task verifier must be nearly perfect, otherwise the agent solves the wrong problem"](https://www.anthropic.com/engineering/building-c-compiler). OpenAI's team reached the same conclusion: [3 engineers produced 1M lines of code](https://openai.com/index/harness-engineering/) not by writing better prompts, but by designing better environments and feedback loops. gruAI's 15-step pipeline IS that harness.
150
-
151
- - **Memory compounds across directives.** Lessons, design rationale, and standing corrections persist in `.context/` and get loaded into every future agent. This implements the [codified context pattern](https://arxiv.org/abs/2602.20478) — hot-memory + specialized agents + cold-memory knowledge base.
106
+ > *The pipeline runs 15 internal steps. Context loading, crash recovery, git isolation, and lesson extraction run automatically between the steps above.*
152
107
 
153
- ---
154
-
155
- ## Why Not Just Use Claude Code Directly?
156
-
157
- Claude Code is the execution engine. gruAI is the management layer on top.
158
-
159
- Without gruAI, you prompt an agent, review the output, re-prompt to fix issues, manage context yourself, and hope nothing falls through the cracks. There is no review gate, no institutional memory, and no structure beyond what you hold in your head.
108
+ ### Weight Adaptation
160
109
 
161
- With gruAI, you hand down a directive and agents self-organize through a 15-step pipeline. Reviews are mandatory and mechanical — a different agent reviews each task, and bash scripts verify the reviews actually happened. Lessons persist across directives so your 10th task runs better than your 1st. You approve the result, not every step along the way.
110
+ Not every directive needs the full process.
162
111
 
163
- gruAI doesn't replace Claude Code. It makes Claude Code work like a team instead of a solo assistant.
112
+ | Weight | Example | Skips | You Decide At |
113
+ |--------|---------|-------|---------------|
114
+ | **Lightweight** | Fix a typo | Debate | Accept only |
115
+ | **Medium** | Add dark mode | Debate | Accept only |
116
+ | **Heavyweight** | New landing page | Nothing | Clarify + Plan + Accept |
117
+ | **Strategic** | Platform migration | Nothing | Clarify + Plan + Accept |
164
118
 
165
119
  ---
166
120
 
@@ -248,6 +202,63 @@ The pipeline and dashboard are engine-agnostic by design — platform adapters h
248
202
 
249
203
  ---
250
204
 
205
+ ## Why Is the Output Better?
206
+
207
+ Every point below traces to published research from Anthropic and OpenAI. This isn't a workflow we invented — it's assembled from what the research says actually works.
208
+
209
+ - **Agents brainstorm and argue before anyone writes code.** For strategic directives, your C-suite agents independently propose approaches, then deliberate — challenging assumptions, resolving disagreements, and surfacing questions for you. Anthropic's research found [multi-agent outperformed single-agent by 90.2%](https://www.anthropic.com/engineering/multi-agent-research-system). The pipeline implements their [orchestrator-workers pattern](https://www.anthropic.com/research/building-effective-agents) where specialized agents collaborate, producing better results than any single agent.
210
+
211
+ - **Reviewers evaluate intent, not just code.** Each reviewer gets [fresh context](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) scoped to the task — they never see the builder's reasoning, preventing confirmation bias. They verify against your Definition of Done (what you asked for), not just whether the code compiles. This is Anthropic's [evaluator-optimizer pattern](https://www.anthropic.com/research/building-effective-agents): one agent generates, another evaluates, issues get fixed in-loop — not after the fact.
212
+
213
+ - **Context is isolated, not accumulated.** Each agent spawns with a [clean context window](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) scoped to exactly what it needs. No 200K-token sessions where the model forgets what it read at the start. Anthropic's context engineering research shows accuracy degrades as token count increases — gruAI treats context as a finite resource under active degradation.
214
+
215
+ - **Verification is mechanical.** Bash scripts — not LLMs — enforce pipeline integrity: schema validation, self-review prevention, step dependency checks, role assignment verification. This follows Anthropic's [poka-yoke principle](https://www.anthropic.com/research/building-effective-agents) (error-proof design) and OpenAI's finding that [invariants should be enforced through structural tests](https://openai.com/index/harness-engineering/), not judgment.
216
+
217
+ - **The harness determines output quality, not model intelligence.** Anthropic found that ["the task verifier must be nearly perfect, otherwise the agent solves the wrong problem"](https://www.anthropic.com/engineering/building-c-compiler). OpenAI's team reached the same conclusion: [3 engineers produced 1M lines of code](https://openai.com/index/harness-engineering/) not by writing better prompts, but by designing better environments and feedback loops. gruAI's 15-step pipeline IS that harness.
218
+
219
+ - **Memory compounds across directives.** Lessons, design rationale, and standing corrections persist in `.context/` and get loaded into every future agent. This implements the [codified context pattern](https://arxiv.org/abs/2602.20478) — hot-memory + specialized agents + cold-memory knowledge base.
220
+
221
+ ---
222
+
223
+ ## Why Not Just Use Claude Code Directly?
224
+
225
+ Claude Code is the execution engine. gruAI is the management layer on top.
226
+
227
+ Without gruAI, you prompt an agent, review the output, re-prompt to fix issues, manage context yourself, and hope nothing falls through the cracks. There is no review gate, no institutional memory, and no structure beyond what you hold in your head.
228
+
229
+ With gruAI, you hand down a directive and agents self-organize through a 15-step pipeline. Reviews are mandatory and mechanical — a different agent reviews each task, and bash scripts verify the reviews actually happened. Lessons persist across directives so your 10th task runs better than your 1st. You approve the result, not every step along the way.
230
+
231
+ gruAI doesn't replace Claude Code. It makes Claude Code work like a team instead of a solo assistant.
232
+
233
+ ---
234
+
235
+ ## The Context Tree
236
+
237
+ All state lives in `.context/` at your repo root — plain markdown and JSON, version-controlled alongside your code.
238
+
239
+ ```
240
+ .context/
241
+ ├── directives/ # All work lives here
242
+ │ └── dark-mode/
243
+ │ ├── directive.json # Pipeline state, weight, progress
244
+ │ ├── directive.md # CEO brief
245
+ │ ├── audit.md # CTO's technical audit
246
+ │ ├── brainstorm.md # C-suite deliberation
247
+ │ └── projects/
248
+ │ └── dark-mode/
249
+ │ └── project.json # Tasks, DOD, agents, reviews
250
+ ├── lessons/ # What went wrong (reactive)
251
+ ├── design/ # Why the system works this way (proactive)
252
+ ├── intel/ # External research from /scout
253
+ └── reports/ # CEO digests
254
+ ```
255
+
256
+ **Directive → Projects → Tasks.** A directive is a unit of work ("add dark mode"). The COO decomposes it into projects, each with tasks, agents, reviewers, and a Definition of Done. `directive.json` tracks pipeline progress — any session can read it and resume where it left off. `project.json` is the source of truth for what needs building and whether it passed review.
257
+
258
+ **Knowledge compounds.** Lessons, design rationale, and standing corrections persist across directives. Agents load relevant context just-in-time — not everything, just what they need for their role and task. No database, no external service — just files.
259
+
260
+ ---
261
+
251
262
  <details>
252
263
  <summary><strong>Terminal Support</strong></summary>
253
264
 
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Scaffolding engine — creates all project files from templates.
3
3
  *
4
+ * SAFE BY DEFAULT: Never overwrites existing user files. Only writes new files.
5
+ * gruai-owned files (agents, skills, registry) are always updated.
6
+ *
4
7
  * Takes an InitConfig and produces:
5
8
  * - .gruai/ canonical home directory
6
9
  * - Platform symlink (.claude/, .aider/, etc.)
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Scaffolding engine — creates all project files from templates.
3
3
  *
4
+ * SAFE BY DEFAULT: Never overwrites existing user files. Only writes new files.
5
+ * gruai-owned files (agents, skills, registry) are always updated.
6
+ *
4
7
  * Takes an InitConfig and produces:
5
8
  * - .gruai/ canonical home directory
6
9
  * - Platform symlink (.claude/, .aider/, etc.)
@@ -25,6 +28,13 @@ function writeFile(filePath, content) {
25
28
  ensureDir(path.dirname(filePath));
26
29
  fs.writeFileSync(filePath, content, 'utf-8');
27
30
  }
31
+ /** Write only if file does not exist. Returns true if written, false if skipped. */
32
+ function writeFileIfNew(filePath, content) {
33
+ if (fs.existsSync(filePath))
34
+ return false;
35
+ writeFile(filePath, content);
36
+ return true;
37
+ }
28
38
  function copyFile(src, dest) {
29
39
  ensureDir(path.dirname(dest));
30
40
  fs.copyFileSync(src, dest);
@@ -64,24 +74,39 @@ function platformDir(platform) {
64
74
  function scaffoldGruaiHome(projectPath, platform) {
65
75
  const gruaiDir = path.join(projectPath, '.gruai');
66
76
  ensureDir(gruaiDir);
67
- // Create platform symlink if applicable
77
+ const merged = [];
68
78
  const platDir = platformDir(platform);
69
79
  if (platDir) {
70
80
  const platPath = path.join(projectPath, platDir);
71
- // If platform dir already exists as a real directory, skip symlink
72
81
  if (fs.existsSync(platPath)) {
73
82
  const stat = fs.lstatSync(platPath);
74
83
  if (stat.isSymbolicLink()) {
84
+ // Already a symlink — check if it points to .gruai
85
+ const target = fs.readlinkSync(platPath);
86
+ if (target === '.gruai' || target === path.join(projectPath, '.gruai')) {
87
+ // Already correct, nothing to do
88
+ return { merged };
89
+ }
75
90
  fs.unlinkSync(platPath);
76
91
  }
77
92
  else {
78
- // Real directory exists -- copy contents into .gruai and replace with symlink
79
- const entries = fs.readdirSync(platPath);
93
+ // Real directory merge contents into .gruai preserving existing files
94
+ const entries = fs.readdirSync(platPath, { withFileTypes: true });
80
95
  for (const entry of entries) {
81
- const src = path.join(platPath, entry);
82
- const dest = path.join(gruaiDir, entry);
83
- if (!fs.existsSync(dest)) {
96
+ const src = path.join(platPath, entry.name);
97
+ const dest = path.join(gruaiDir, entry.name);
98
+ if (fs.existsSync(dest)) {
99
+ // Destination exists — merge directories, skip files
100
+ if (entry.isDirectory() && fs.statSync(dest).isDirectory()) {
101
+ // Merge directory contents (existing files in .gruai win)
102
+ mergeDir(src, dest);
103
+ merged.push(entry.name + '/');
104
+ }
105
+ // Skip files that already exist in .gruai
106
+ }
107
+ else {
84
108
  fs.renameSync(src, dest);
109
+ merged.push(entry.name);
85
110
  }
86
111
  }
87
112
  fs.rmSync(platPath, { recursive: true, force: true });
@@ -90,13 +115,33 @@ function scaffoldGruaiHome(projectPath, platform) {
90
115
  // Create symlink: .claude -> .gruai
91
116
  fs.symlinkSync('.gruai', platPath);
92
117
  }
118
+ return { merged };
119
+ }
120
+ /** Recursively merge src into dest, never overwriting existing files in dest. */
121
+ function mergeDir(src, dest) {
122
+ ensureDir(dest);
123
+ const entries = fs.readdirSync(src, { withFileTypes: true });
124
+ for (const entry of entries) {
125
+ const srcPath = path.join(src, entry.name);
126
+ const destPath = path.join(dest, entry.name);
127
+ if (entry.isDirectory()) {
128
+ mergeDir(srcPath, destPath);
129
+ }
130
+ else if (!fs.existsSync(destPath)) {
131
+ fs.renameSync(srcPath, destPath);
132
+ }
133
+ // If destPath exists, user's file wins — do nothing
134
+ }
93
135
  }
94
136
  function scaffoldAgents(projectPath, agents) {
95
137
  const destDir = path.join(projectPath, '.gruai', 'agents');
96
- let count = 0;
138
+ let written = 0;
139
+ const skipped = [];
97
140
  for (const agent of agents) {
98
141
  const roleId = ROLE_DEFINITIONS.find(r => r.title === agent.title)?.id;
99
142
  const templatePath = path.join(ROLE_TEMPLATES_DIR, `${roleId}.md`);
143
+ const destPath = path.join(destDir, agent.agentFile);
144
+ // Agent personality files are gruai-owned — always write
100
145
  let content;
101
146
  if (fs.existsSync(templatePath)) {
102
147
  content = fs.readFileSync(templatePath, 'utf-8');
@@ -107,10 +152,10 @@ function scaffoldAgents(projectPath, agents) {
107
152
  else {
108
153
  content = `# ${agent.name} -- ${agent.role}\n\nRole template not found.\n`;
109
154
  }
110
- writeFile(path.join(destDir, agent.agentFile), content);
111
- count++;
155
+ writeFile(destPath, content);
156
+ written++;
112
157
  }
113
- return count;
158
+ return { written, skipped };
114
159
  }
115
160
  function scaffoldRegistry(projectPath, agents, preset) {
116
161
  const ceoEntry = {
@@ -148,6 +193,7 @@ function scaffoldRegistry(projectPath, agents, preset) {
148
193
  }));
149
194
  const teams = buildTeams(agents);
150
195
  const registry = { teamSize: preset, agents: [ceoEntry, ...agentEntries], teams };
196
+ // Registry is gruai-owned — always overwrite
151
197
  writeFile(path.join(projectPath, '.gruai', 'agent-registry.json'), JSON.stringify(registry, null, 2));
152
198
  }
153
199
  function buildTeams(agents) {
@@ -201,7 +247,8 @@ function buildTeams(agents) {
201
247
  }
202
248
  function scaffoldSkills(projectPath) {
203
249
  const destDir = path.join(projectPath, '.gruai', 'skills');
204
- let count = 0;
250
+ let written = 0;
251
+ let updated = 0;
205
252
  for (const skill of ALL_SKILLS) {
206
253
  const skillDir = path.join(SKILLS_SRC_DIR, skill);
207
254
  const skillMd = path.join(skillDir, 'SKILL.md');
@@ -209,28 +256,52 @@ function scaffoldSkills(projectPath) {
209
256
  console.warn(c.yellow(` Warning: Skill file not found: ${skill}/SKILL.md (skipped)`));
210
257
  continue;
211
258
  }
212
- copyFile(skillMd, path.join(destDir, skill, 'SKILL.md'));
259
+ const destSkillMd = path.join(destDir, skill, 'SKILL.md');
260
+ const existed = fs.existsSync(destSkillMd);
261
+ // Skills are gruai-owned — always update to latest version
262
+ copyFile(skillMd, destSkillMd);
213
263
  const docsDir = path.join(skillDir, 'docs');
214
264
  if (fs.existsSync(docsDir) && fs.statSync(docsDir).isDirectory()) {
215
265
  copyDirRecursive(docsDir, path.join(destDir, skill, 'docs'));
216
266
  }
217
- count++;
267
+ if (existed)
268
+ updated++;
269
+ else
270
+ written++;
218
271
  }
219
- return count;
272
+ return { written, updated };
220
273
  }
221
274
  function scaffoldContext(projectPath, config) {
222
275
  const contextDir = path.join(projectPath, '.context');
223
- // vision.md
276
+ const created = [];
277
+ const preserved = [];
278
+ // vision.md — user-owned, skip if exists
279
+ const visionPath = path.join(contextDir, 'vision.md');
224
280
  const vision = readTemplate('vision.md').replace(/\{\{PROJECT_NAME\}\}/g, config.projectName);
225
- writeFile(path.join(contextDir, 'vision.md'), vision);
226
- // lessons/index.md
281
+ if (writeFileIfNew(visionPath, vision))
282
+ created.push('vision.md');
283
+ else
284
+ preserved.push('vision.md');
285
+ // lessons/index.md — user-owned, skip if exists
286
+ const lessonsPath = path.join(contextDir, 'lessons', 'index.md');
227
287
  const lessons = readTemplate('lessons.md').replace(/\{\{PROJECT_NAME\}\}/g, config.projectName);
228
- writeFile(path.join(contextDir, 'lessons', 'index.md'), lessons);
229
- // preferences.md
230
- writeFile(path.join(contextDir, 'preferences.md'), `# CEO Preferences\n\n> Standing orders for the team. Agents read this before every task.\n\n## Standing Orders\n\n- (Add your preferences here)\n`);
231
- // backlog.json
288
+ if (writeFileIfNew(lessonsPath, lessons))
289
+ created.push('lessons/index.md');
290
+ else
291
+ preserved.push('lessons/index.md');
292
+ // preferences.md — user-owned, skip if exists
293
+ const prefsPath = path.join(contextDir, 'preferences.md');
294
+ if (writeFileIfNew(prefsPath, `# CEO Preferences\n\n> Standing orders for the team. Agents read this before every task.\n\n## Standing Orders\n\n- (Add your preferences here)\n`))
295
+ created.push('preferences.md');
296
+ else
297
+ preserved.push('preferences.md');
298
+ // backlog.json — user-owned, skip if exists
299
+ const backlogPath = path.join(contextDir, 'backlog.json');
232
300
  const backlog = readTemplate('backlog.json.template');
233
- writeFile(path.join(contextDir, 'backlog.json'), backlog);
301
+ if (writeFileIfNew(backlogPath, backlog))
302
+ created.push('backlog.json');
303
+ else
304
+ preserved.push('backlog.json');
234
305
  // Empty directories with .gitkeep
235
306
  for (const dir of ['directives', 'reports']) {
236
307
  const dirPath = path.join(contextDir, dir);
@@ -240,8 +311,14 @@ function scaffoldContext(projectPath, config) {
240
311
  fs.writeFileSync(gitkeep, '', 'utf-8');
241
312
  }
242
313
  }
314
+ return { created, preserved };
243
315
  }
244
316
  function scaffoldClaudeMd(projectPath, config) {
317
+ const claudeMdPath = path.join(projectPath, 'CLAUDE.md');
318
+ // User-owned file — never overwrite
319
+ if (fs.existsSync(claudeMdPath)) {
320
+ return 'preserved';
321
+ }
245
322
  const template = readTemplate('CLAUDE.md.template');
246
323
  const rosterLines = ['| Name | Title | Role |', '|------|-------|------|'];
247
324
  rosterLines.push('| (You) | CEO | Chief Executive Officer |');
@@ -251,9 +328,12 @@ function scaffoldClaudeMd(projectPath, config) {
251
328
  const content = template
252
329
  .replace(/\{\{PROJECT_NAME\}\}/g, config.projectName)
253
330
  .replace(/\{\{AGENT_ROSTER\}\}/g, rosterLines.join('\n'));
254
- writeFile(path.join(projectPath, 'CLAUDE.md'), content);
331
+ writeFile(claudeMdPath, content);
332
+ return 'created';
255
333
  }
256
334
  function scaffoldGruaiConfig(projectPath, config) {
335
+ const configPath = path.join(projectPath, 'gruai.config.json');
336
+ const existed = fs.existsSync(configPath);
257
337
  const template = readTemplate('gruai.config.json.template');
258
338
  const agentsJson = JSON.stringify(config.agents.map(a => ({ id: a.id, name: a.name, role: a.title })), null, 4);
259
339
  const indentedAgentsJson = agentsJson
@@ -265,19 +345,25 @@ function scaffoldGruaiConfig(projectPath, config) {
265
345
  .replace(/\{\{PRESET\}\}/g, config.preset)
266
346
  .replace(/\{\{PLATFORM\}\}/g, config.platform)
267
347
  .replace(/\{\{AGENTS_JSON\}\}/g, indentedAgentsJson);
268
- writeFile(path.join(projectPath, 'gruai.config.json'), content);
348
+ // gruai config is gruai-owned — always update
349
+ writeFile(configPath, content);
350
+ return existed ? 'updated' : 'created';
269
351
  }
270
352
  function scaffoldWelcomeDirective(projectPath) {
271
353
  const srcDir = path.join(TEMPLATES_DIR, 'welcome-directive');
272
354
  if (!fs.existsSync(srcDir))
273
- return;
355
+ return false;
274
356
  const destDir = path.join(projectPath, '.context', 'directives', 'welcome');
357
+ // User-owned content — skip if directive already exists
358
+ if (fs.existsSync(path.join(destDir, 'directive.json')))
359
+ return false;
275
360
  ensureDir(destDir);
276
361
  // directive.json
277
362
  const djson = fs.readFileSync(path.join(srcDir, 'directive.json'), 'utf-8');
278
363
  writeFile(path.join(destDir, 'directive.json'), djson.replace(/\{\{CREATED_AT\}\}/g, new Date().toISOString()));
279
364
  // directive.md
280
365
  copyFile(path.join(srcDir, 'directive.md'), path.join(destDir, 'directive.md'));
366
+ return true;
281
367
  }
282
368
  // ─── Main scaffold function ─────────────────────────────────────────────────
283
369
  export async function runScaffold(config) {
@@ -287,35 +373,55 @@ export async function runScaffold(config) {
287
373
  }
288
374
  console.log(`\n ${c.bold('Scaffolding gruai...')}\n`);
289
375
  // 1. .gruai/ home + platform symlink
290
- scaffoldGruaiHome(config.projectPath, config.platform);
376
+ const { merged } = scaffoldGruaiHome(config.projectPath, config.platform);
291
377
  const platDir = platformDir(config.platform);
292
378
  if (platDir) {
293
379
  console.log(c.green(` [+] Home: .gruai/ with ${platDir}/ -> .gruai/ symlink`));
380
+ if (merged.length > 0) {
381
+ console.log(c.dim(` merged ${merged.length} existing entries from ${platDir}/`));
382
+ }
294
383
  }
295
384
  else {
296
385
  console.log(c.green(` [+] Home: .gruai/`));
297
386
  }
298
- // 2. Agent registry
387
+ // 2. Agent registry (gruai-owned — always update)
299
388
  scaffoldRegistry(config.projectPath, config.agents, config.preset);
300
- console.log(c.green(` [+] Registry: .gruai/agent-registry.json (${config.agents.length} agents + CEO, ${config.preset} preset)`));
301
- // 3. Agent personality files
302
- const agentCount = scaffoldAgents(config.projectPath, config.agents);
303
- console.log(c.green(` [+] Agents: ${agentCount} personality files`));
304
- // 4. Skills
305
- const skillCount = scaffoldSkills(config.projectPath);
306
- console.log(c.green(` [+] Skills: ${skillCount} skill definitions`));
307
- // 5. Context tree
308
- scaffoldContext(config.projectPath, config);
309
- console.log(c.green(` [+] Context: vision.md, lessons/, directives/, backlog.json`));
310
- // 6. CLAUDE.md
311
- scaffoldClaudeMd(config.projectPath, config);
312
- console.log(c.green(` [+] CLAUDE.md: project rules with agent roster`));
313
- // 7. gruai.config.json
314
- scaffoldGruaiConfig(config.projectPath, config);
315
- console.log(c.green(` [+] Config: gruai.config.json`));
316
- // 8. Welcome directive
317
- scaffoldWelcomeDirective(config.projectPath);
318
- console.log(c.green(` [+] Directive: welcome directive scaffolded`));
389
+ console.log(c.green(` [+] Registry: agent-registry.json (${config.agents.length} agents + CEO, ${config.preset} preset)`));
390
+ // 3. Agent personality files (gruai-owned — always update)
391
+ const agentResult = scaffoldAgents(config.projectPath, config.agents);
392
+ console.log(c.green(` [+] Agents: ${agentResult.written} personality files`));
393
+ // 4. Skills (gruai-owned — always update to latest)
394
+ const skillResult = scaffoldSkills(config.projectPath);
395
+ const skillParts = [];
396
+ if (skillResult.written > 0)
397
+ skillParts.push(`${skillResult.written} new`);
398
+ if (skillResult.updated > 0)
399
+ skillParts.push(`${skillResult.updated} updated`);
400
+ console.log(c.green(` [+] Skills: ${skillParts.join(', ') || 'up to date'}`));
401
+ // 5. Context tree (user-owned — never overwrite)
402
+ const ctxResult = scaffoldContext(config.projectPath, config);
403
+ if (ctxResult.created.length > 0) {
404
+ console.log(c.green(` [+] Context: ${ctxResult.created.join(', ')}`));
405
+ }
406
+ if (ctxResult.preserved.length > 0) {
407
+ console.log(c.dim(` [=] Context: ${ctxResult.preserved.join(', ')} (preserved)`));
408
+ }
409
+ // 6. CLAUDE.md (user-owned — never overwrite)
410
+ const claudeResult = scaffoldClaudeMd(config.projectPath, config);
411
+ if (claudeResult === 'created') {
412
+ console.log(c.green(` [+] CLAUDE.md: project rules with agent roster`));
413
+ }
414
+ else {
415
+ console.log(c.dim(` [=] CLAUDE.md: preserved (existing file kept)`));
416
+ }
417
+ // 7. gruai.config.json (gruai-owned — always update)
418
+ const configResult = scaffoldGruaiConfig(config.projectPath, config);
419
+ console.log(c.green(` [+] Config: gruai.config.json (${configResult})`));
420
+ // 8. Welcome directive (user-owned — skip if exists)
421
+ const welcomeCreated = scaffoldWelcomeDirective(config.projectPath);
422
+ if (welcomeCreated) {
423
+ console.log(c.green(` [+] Directive: welcome directive scaffolded`));
424
+ }
319
425
  // Output team summary
320
426
  console.log(`\n ${c.bold('Done!')} gruai scaffolded into: ${c.cyan(config.projectPath)}\n`);
321
427
  console.log(` ${c.bold('Your team:')}\n`);
@@ -333,10 +439,10 @@ export async function runScaffold(config) {
333
439
  ${c.dim(path.join(config.projectPath, '.context', 'preferences.md'))}
334
440
 
335
441
  3. Start the dashboard:
336
- ${c.cyan('gru-ai start')}
442
+ ${c.cyan('npx gru-ai start')}
337
443
 
338
- 4. Create your first directive:
339
- ${c.cyan('claude -p "/directive welcome"')}
444
+ 4. Give your first directive:
445
+ ${c.cyan('claude -p "/directive add dark mode to the dashboard"')}
340
446
 
341
447
  ${c.dim('Happy orchestrating!')}
342
448
  `);
@@ -14,15 +14,15 @@ function printStartHelp() {
14
14
  ${c.bold('gruai start')} — Launch the dashboard server
15
15
 
16
16
  ${c.bold('Usage:')}
17
- gru-ai start [options]
17
+ npx gru-ai start [options]
18
18
 
19
19
  ${c.bold('Options:')}
20
20
  --port <port> Server port (default: 4444)
21
21
  --help Show this help message
22
22
 
23
23
  ${c.bold('Examples:')}
24
- gru-ai start
25
- gru-ai start --port 8080
24
+ npx gru-ai start
25
+ npx gru-ai start --port 8080
26
26
  `);
27
27
  }
28
28
  function isInitialized(projectPath) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gru-ai",
3
3
  "private": false,
4
- "version": "0.3.0",
4
+ "version": "0.3.1",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "gru-ai": "dist-cli/index.js"