homunculus-code 0.1.0 → 0.3.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.
- package/ARCHITECTURE.md +211 -0
- package/README.md +57 -17
- package/bin/cli.js +36 -0
- package/bin/init.js +28 -203
- package/bin/night.js +292 -0
- package/commands/hm-night.md +86 -0
- package/commands/hm-setup.md +65 -0
- package/commands/hm-status.md +47 -0
- package/examples/reference/README.md +13 -1
- package/examples/reference/evolved-skills/claude-code-reference/ch01-extensions.md +98 -0
- package/examples/reference/evolved-skills/claude-code-reference/ch02-agents.md +90 -0
- package/examples/reference/evolved-skills/claude-code-reference/ch03-hooks.md +104 -0
- package/examples/reference/evolved-skills/claude-code-reference/ch04-mcp.md +78 -0
- package/examples/reference/evolved-skills/claude-code-reference/ch05-ui.md +161 -0
- package/examples/reference/evolved-skills/claude-code-reference/ch06-rules-security.md +301 -0
- package/examples/reference/evolved-skills/claude-code-reference/ch07-model-memory.md +203 -0
- package/examples/reference/evolved-skills/claude-code-reference/ch08-workflows.md +148 -0
- package/examples/reference/evolved-skills/claude-code-reference/ch09-integrations.md +502 -0
- package/examples/reference/evolved-skills/claude-code-reference/ch10-cli-sdk.md +269 -0
- package/examples/reference/evolved-skills/claude-code-reference/ch11-output-versions.md +172 -0
- package/examples/reference/evolved-skills/claude-code-reference/index.md +134 -0
- package/package.json +2 -2
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Architecture: Goal-Tree-Driven Evolution
|
|
2
|
+
|
|
3
|
+
This document explains the design philosophy behind Homunculus.
|
|
4
|
+
|
|
5
|
+
## The Problem
|
|
6
|
+
|
|
7
|
+
AI assistants are statically configured. You write rules, add skills, configure hooks — but the AI never improves on its own. Every improvement requires human effort:
|
|
8
|
+
|
|
9
|
+
1. Notice something could be better
|
|
10
|
+
2. Research the solution
|
|
11
|
+
3. Implement it (skill, hook, rule, script)
|
|
12
|
+
4. Test it manually
|
|
13
|
+
5. Maintain it when things change
|
|
14
|
+
|
|
15
|
+
This doesn't scale. As your system grows, maintenance becomes a full-time job.
|
|
16
|
+
|
|
17
|
+
## The Solution: Goal Trees
|
|
18
|
+
|
|
19
|
+
Instead of configuring individual behaviors, you define **what you want** in a tree of goals. The system figures out **how to achieve it** — and keeps improving the "how" over time.
|
|
20
|
+
|
|
21
|
+
### Why a Tree?
|
|
22
|
+
|
|
23
|
+
Goals are naturally hierarchical:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
"Ship better software"
|
|
27
|
+
├── "Write fewer bugs"
|
|
28
|
+
│ ├── "Every change has tests"
|
|
29
|
+
│ └── "Catch issues before merge"
|
|
30
|
+
└── "Move faster"
|
|
31
|
+
├── "Automate repetitive tasks"
|
|
32
|
+
└── "Debug faster"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
A tree structure gives you:
|
|
36
|
+
- **Decomposition** — Break big goals into measurable sub-goals
|
|
37
|
+
- **Priority** — Unhealthy sub-goals bubble up to their parent
|
|
38
|
+
- **Independence** — Each sub-goal can be implemented differently
|
|
39
|
+
- **Replaceability** — Swap implementations without affecting goals
|
|
40
|
+
|
|
41
|
+
### Goal Node Schema
|
|
42
|
+
|
|
43
|
+
Every node in the tree follows the same schema:
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
goal_name:
|
|
47
|
+
purpose: "Why this goal exists" # Never changes
|
|
48
|
+
realized_by: path/to/implementation # Changes as system evolves
|
|
49
|
+
metrics:
|
|
50
|
+
- name: metric_name
|
|
51
|
+
source: where to get the data
|
|
52
|
+
healthy: "what healthy looks like" # Defines success
|
|
53
|
+
health_check:
|
|
54
|
+
command: "shell command" # Machine-executable
|
|
55
|
+
expected: "human description" # For readability
|
|
56
|
+
goals:
|
|
57
|
+
sub_goal_1: ... # Recursive
|
|
58
|
+
sub_goal_2: ...
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### The `realized_by` Field
|
|
62
|
+
|
|
63
|
+
This is the key innovation. It decouples **what** (the goal) from **how** (the implementation). The value can be:
|
|
64
|
+
|
|
65
|
+
- A skill: `skills/tdd-workflow.md`
|
|
66
|
+
- An agent: `agents/code-reviewer.md`
|
|
67
|
+
- A hook: `hooks/pre-commit.sh`
|
|
68
|
+
- A script: `scripts/deploy.sh`
|
|
69
|
+
- A cron job: `launchd/nightly.plist`
|
|
70
|
+
- An MCP server: `mcp-servers/github`
|
|
71
|
+
- A rule: `rules/security.md`
|
|
72
|
+
- A slash command: `commands/quality-gate.md`
|
|
73
|
+
- Or anything else
|
|
74
|
+
|
|
75
|
+
The evolution system can **replace** the implementation at any time, as long as the goal's health check still passes. This is what makes the system truly self-improving — it's not locked into any particular approach.
|
|
76
|
+
|
|
77
|
+
## Evolution Pipeline
|
|
78
|
+
|
|
79
|
+
### Layer 1: Observation → Instincts
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
Tool usage → observe.sh (hook) → observations.jsonl
|
|
83
|
+
│
|
|
84
|
+
evaluate-session.js (SessionEnd)
|
|
85
|
+
│
|
|
86
|
+
▼
|
|
87
|
+
instincts/personal/*.md
|
|
88
|
+
(confidence-scored patterns)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Instincts are small behavioral patterns with:
|
|
92
|
+
- **Confidence scores** — increase with reinforcement, decay over time
|
|
93
|
+
- **Half-life decay** — unused instincts fade (default: 90 days)
|
|
94
|
+
- **Automatic archival** — `prune-instincts.js` archives low-value ones
|
|
95
|
+
|
|
96
|
+
### Layer 2: Convergence → Skills
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
Related instincts (3+) → /evolve → evolved/skills/*.md
|
|
100
|
+
│
|
|
101
|
+
eval spec (scenarios)
|
|
102
|
+
│
|
|
103
|
+
/eval-skill → score
|
|
104
|
+
│
|
|
105
|
+
/improve-skill → iterate
|
|
106
|
+
│
|
|
107
|
+
100% pass rate
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Skills are:
|
|
111
|
+
- **Tested** — every skill has an eval spec with scenario tests
|
|
112
|
+
- **Versioned** — changes tracked with semver
|
|
113
|
+
- **Quality-gated** — must pass eval before adoption
|
|
114
|
+
- **Regression-protected** — rollback if quality drops
|
|
115
|
+
|
|
116
|
+
### Layer 3: Goal-Directed Evolution
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
architecture.yaml
|
|
120
|
+
│
|
|
121
|
+
▼
|
|
122
|
+
health_check.command → pass/fail per goal
|
|
123
|
+
│
|
|
124
|
+
▼
|
|
125
|
+
Unhealthy goals get priority
|
|
126
|
+
│
|
|
127
|
+
▼
|
|
128
|
+
Evolution engine focuses improvement
|
|
129
|
+
on the weakest areas
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The goal tree adds **direction** to evolution. Without it, the system learns whatever patterns happen to occur. With it, the system asks: "which goals are failing?" and focuses there.
|
|
133
|
+
|
|
134
|
+
### Layer 4: Autonomous Operation (Nightly Agent)
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
launchd/cron → heartbeat.sh (scheduled)
|
|
138
|
+
│
|
|
139
|
+
┌───────────────┼───────────────┐
|
|
140
|
+
▼ ▼ ▼
|
|
141
|
+
Health Check Evolve Pipeline Research
|
|
142
|
+
│ │ │
|
|
143
|
+
▼ ▼ ▼
|
|
144
|
+
Identify weak eval → improve Scan for better
|
|
145
|
+
goals → prune approaches
|
|
146
|
+
│ │ │
|
|
147
|
+
└───────────────┼───────────────┘
|
|
148
|
+
▼
|
|
149
|
+
Morning Report
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The nightly agent closes the loop — no human intervention needed for routine evolution.
|
|
153
|
+
|
|
154
|
+
### Layer 5: Meta-Evolution
|
|
155
|
+
|
|
156
|
+
The evolution mechanism itself is measured and adjusted:
|
|
157
|
+
|
|
158
|
+
| Metric | What it measures | Action if unhealthy |
|
|
159
|
+
|--------|-----------------|-------------------|
|
|
160
|
+
| `instinct_survival_rate` | % of instincts surviving 14 days | Raise extraction thresholds |
|
|
161
|
+
| `skill_convergence` | Time from first instinct to skill | Adjust aggregation triggers |
|
|
162
|
+
| `eval_discrimination` | % of scenarios that distinguish versions | Add harder boundary scenarios |
|
|
163
|
+
|
|
164
|
+
This prevents the system from degenerating — if it's extracting too many low-quality instincts, it automatically becomes more selective.
|
|
165
|
+
|
|
166
|
+
## Design Principles
|
|
167
|
+
|
|
168
|
+
### 1. Goals Over Implementations
|
|
169
|
+
|
|
170
|
+
Never optimize an implementation directly. Always ask: "which goal does this serve?" If there's no goal, the implementation shouldn't exist.
|
|
171
|
+
|
|
172
|
+
### 2. Measure Everything
|
|
173
|
+
|
|
174
|
+
If you can't measure it, you can't evolve it. Every goal should eventually have a `health_check` or `metrics` entry. Start with approximate metrics and refine them.
|
|
175
|
+
|
|
176
|
+
### 3. Replaceable Everything
|
|
177
|
+
|
|
178
|
+
No implementation is sacred. A skill can be replaced by a hook. A script can be replaced by an agent. The only constant is the goal tree.
|
|
179
|
+
|
|
180
|
+
### 4. Safe Evolution
|
|
181
|
+
|
|
182
|
+
- Eval specs prevent regression
|
|
183
|
+
- Experiments run in isolated worktrees
|
|
184
|
+
- Rollback if quality drops
|
|
185
|
+
- Noise tolerance (5pp) prevents chasing statistical artifacts
|
|
186
|
+
|
|
187
|
+
### 5. Progressive Complexity
|
|
188
|
+
|
|
189
|
+
Start simple:
|
|
190
|
+
1. Just the goal tree + observation hook
|
|
191
|
+
2. Let instincts accumulate naturally
|
|
192
|
+
3. Evolve first skill when you have enough instincts
|
|
193
|
+
4. Add eval spec for quality control
|
|
194
|
+
5. Set up nightly agent when you're ready for autonomy
|
|
195
|
+
|
|
196
|
+
Don't try to build the full system on day one. Let it grow.
|
|
197
|
+
|
|
198
|
+
## Comparison with Other Approaches
|
|
199
|
+
|
|
200
|
+
| Approach | Optimizes | Direction | Quality Control | Autonomous |
|
|
201
|
+
|----------|-----------|-----------|----------------|------------|
|
|
202
|
+
| Manual rules | Individual behaviors | Human-directed | None | No |
|
|
203
|
+
| Claude Memory | Fact recall | Usage-driven | None | No |
|
|
204
|
+
| OpenClaw skills | Skill generation | Human-triggered | None | Partial |
|
|
205
|
+
| **Homunculus** | **Goal achievement** | **Goal-tree-driven** | **Eval specs** | **Yes (nightly)** |
|
|
206
|
+
|
|
207
|
+
## Further Reading
|
|
208
|
+
|
|
209
|
+
- [README.md](README.md) — Quick start and overview
|
|
210
|
+
- [docs/nightly-agent.md](docs/nightly-agent.md) — Setting up autonomous operation
|
|
211
|
+
- [examples/reference/](examples/reference/) — Real-world system after 15 days
|
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Homunculus for Claude Code
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/homunculus-code)
|
|
3
4
|
[](https://opensource.org/licenses/MIT)
|
|
4
5
|
[](https://docs.anthropic.com/en/docs/claude-code)
|
|
5
6
|
[](https://nodejs.org)
|
|
@@ -153,35 +154,74 @@ The evolution engine then:
|
|
|
153
154
|
npx homunculus-code init
|
|
154
155
|
```
|
|
155
156
|
|
|
156
|
-
|
|
157
|
+
```
|
|
158
|
+
Homunculus — Self-evolving AI Assistant
|
|
159
|
+
|
|
160
|
+
✓ Created homunculus/ directory structure
|
|
161
|
+
✓ Added evolution rules
|
|
162
|
+
✓ Copied evolution scripts
|
|
163
|
+
✓ Added slash commands (/hm-setup, /hm-night, /hm-status)
|
|
164
|
+
✓ Configured observation hook
|
|
157
165
|
|
|
166
|
+
Done! Homunculus is installed.
|
|
167
|
+
|
|
168
|
+
Next steps:
|
|
169
|
+
1. Run claude to open Claude Code
|
|
170
|
+
2. Type /hm-setup to define your goals (AI-guided)
|
|
171
|
+
3. Type /hm-night to run your first evolution cycle
|
|
158
172
|
```
|
|
159
|
-
🧬 Homunculus — Self-evolving AI Assistant
|
|
160
173
|
|
|
161
|
-
|
|
162
|
-
? What's your main goal? Build a reliable SaaS product
|
|
174
|
+
### 2. Define Your Goals
|
|
163
175
|
|
|
164
|
-
|
|
165
|
-
✅ Generated architecture.yaml with your goals
|
|
166
|
-
✅ Added observation hook to Claude Code
|
|
167
|
-
✅ Copied evolution scripts
|
|
176
|
+
Open Claude Code and type `/hm-setup`. Claude will have a short conversation with you to understand your project and goals, then generate your `architecture.yaml` automatically.
|
|
168
177
|
|
|
169
|
-
Done! Start using Claude Code. Your assistant will evolve.
|
|
170
178
|
```
|
|
179
|
+
> /hm-setup
|
|
171
180
|
|
|
172
|
-
|
|
181
|
+
Claude: What kind of project is this?
|
|
182
|
+
You: A SaaS app for team collaboration
|
|
173
183
|
|
|
174
|
-
|
|
184
|
+
Claude: What do you spend most time on?
|
|
185
|
+
You: Debugging auth issues and writing tests
|
|
175
186
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
187
|
+
Claude: Here's your goal tree:
|
|
188
|
+
🎯 Team Collaboration SaaS
|
|
189
|
+
├── code_quality — Ship fewer bugs
|
|
190
|
+
│ ├── testing — Every change has tests
|
|
191
|
+
│ └── auth_reliability — Auth works every time
|
|
192
|
+
├── productivity — Move faster
|
|
193
|
+
│ └── debugging — Find root causes faster
|
|
194
|
+
└── knowledge — Stay current
|
|
195
|
+
└── tool_updates — Track Claude Code updates
|
|
196
|
+
|
|
197
|
+
Does this look right?
|
|
198
|
+
You: Yes!
|
|
199
|
+
|
|
200
|
+
Claude: ✅ architecture.yaml created with 5 goals!
|
|
180
201
|
```
|
|
181
202
|
|
|
182
|
-
### 3.
|
|
203
|
+
### 3. Run Your First Evolution Cycle
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
> /hm-night
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Watch Claude check your goals, scan for patterns, evaluate skills, and generate a report — all in one command. This is what the nightly agent does autonomously while you sleep.
|
|
210
|
+
|
|
211
|
+
### 4. Keep Using Claude Code
|
|
212
|
+
|
|
213
|
+
The observation hook watches your usage automatically. As patterns emerge:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
/hm-night Run an evolution cycle
|
|
217
|
+
/hm-status Check evolution progress
|
|
218
|
+
/hm-setup Refine your goals anytime
|
|
219
|
+
/eval-skill Evaluate a specific skill
|
|
220
|
+
/improve-skill Auto-improve a skill
|
|
221
|
+
/evolve Converge instincts into skills
|
|
222
|
+
```
|
|
183
223
|
|
|
184
|
-
|
|
224
|
+
Set up the [nightly agent](docs/nightly-agent.md) to run `/hm-night` autonomously while you sleep.
|
|
185
225
|
|
|
186
226
|
---
|
|
187
227
|
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// homunculus-code CLI — entry point
|
|
3
|
+
|
|
4
|
+
const command = process.argv[2];
|
|
5
|
+
|
|
6
|
+
switch (command) {
|
|
7
|
+
case 'init':
|
|
8
|
+
require('./init.js');
|
|
9
|
+
break;
|
|
10
|
+
case 'night':
|
|
11
|
+
require('./night.js');
|
|
12
|
+
break;
|
|
13
|
+
case 'help':
|
|
14
|
+
case '--help':
|
|
15
|
+
case '-h':
|
|
16
|
+
case undefined:
|
|
17
|
+
console.log('');
|
|
18
|
+
console.log(' \x1b[1mHomunculus\x1b[0m — Self-evolving AI Assistant for Claude Code');
|
|
19
|
+
console.log('');
|
|
20
|
+
console.log(' Usage:');
|
|
21
|
+
console.log(' npx homunculus-code <command>');
|
|
22
|
+
console.log('');
|
|
23
|
+
console.log(' Commands:');
|
|
24
|
+
console.log(' init Set up Homunculus in your project');
|
|
25
|
+
console.log(' night Run one evolution cycle (health check → evolve → report)');
|
|
26
|
+
console.log(' help Show this help message');
|
|
27
|
+
console.log('');
|
|
28
|
+
console.log(' After init, use Claude Code normally. Evolution happens automatically.');
|
|
29
|
+
console.log(' Run "night" anytime to trigger a manual evolution cycle.');
|
|
30
|
+
console.log('');
|
|
31
|
+
break;
|
|
32
|
+
default:
|
|
33
|
+
console.error(` Unknown command: ${command}`);
|
|
34
|
+
console.error(' Run "npx homunculus-code help" for available commands.');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
package/bin/init.js
CHANGED
|
@@ -1,44 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// homunculus init — Set up
|
|
2
|
+
// homunculus init — Set up the evolution structure in your project
|
|
3
3
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
|
-
const readline = require('readline');
|
|
7
6
|
|
|
8
7
|
const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
|
|
9
8
|
const CORE_DIR = path.join(__dirname, '..', 'core');
|
|
10
9
|
const COMMANDS_DIR = path.join(__dirname, '..', 'commands');
|
|
11
10
|
|
|
12
|
-
const YES_MODE = process.argv.includes('--yes') || process.argv.includes('-y');
|
|
13
|
-
|
|
14
|
-
let rl;
|
|
15
|
-
if (!YES_MODE) {
|
|
16
|
-
rl = readline.createInterface({
|
|
17
|
-
input: process.stdin,
|
|
18
|
-
output: process.stdout
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function ask(question, defaultVal) {
|
|
23
|
-
if (YES_MODE) return Promise.resolve(process.env[`HOMUNCULUS_${question.replace(/[^A-Z]/gi, '_').toUpperCase()}`] || defaultVal || '');
|
|
24
|
-
return new Promise(resolve => {
|
|
25
|
-
const suffix = defaultVal ? ` (${defaultVal})` : '';
|
|
26
|
-
rl.question(`${question}${suffix}: `, answer => {
|
|
27
|
-
resolve(answer.trim() || defaultVal || '');
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
11
|
function ensureDir(dir) {
|
|
33
12
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
34
13
|
}
|
|
35
14
|
|
|
36
|
-
function copyFile(src, dest) {
|
|
37
|
-
if (fs.existsSync(src)) {
|
|
38
|
-
fs.copyFileSync(src, dest);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
15
|
function copyDir(src, dest) {
|
|
43
16
|
ensureDir(dest);
|
|
44
17
|
if (!fs.existsSync(src)) return;
|
|
@@ -53,18 +26,9 @@ function copyDir(src, dest) {
|
|
|
53
26
|
}
|
|
54
27
|
}
|
|
55
28
|
|
|
56
|
-
function
|
|
57
|
-
let result = content;
|
|
58
|
-
for (const [key, value] of Object.entries(vars)) {
|
|
59
|
-
result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value);
|
|
60
|
-
}
|
|
61
|
-
return result;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async function main() {
|
|
29
|
+
function main() {
|
|
65
30
|
console.log('');
|
|
66
31
|
console.log(' \x1b[1mHomunculus\x1b[0m — Self-evolving AI Assistant');
|
|
67
|
-
console.log(' A seed that grows into your own AI assistant.');
|
|
68
32
|
console.log('');
|
|
69
33
|
|
|
70
34
|
const projectDir = process.cwd();
|
|
@@ -75,128 +39,6 @@ async function main() {
|
|
|
75
39
|
console.log('');
|
|
76
40
|
}
|
|
77
41
|
|
|
78
|
-
// Gather info
|
|
79
|
-
const projectName = await ask(' Project name', path.basename(projectDir));
|
|
80
|
-
const purpose = await ask(' What is this project\'s main goal?', 'My evolving AI assistant');
|
|
81
|
-
|
|
82
|
-
console.log('');
|
|
83
|
-
console.log(' Select areas you want your AI to improve in:');
|
|
84
|
-
console.log('');
|
|
85
|
-
|
|
86
|
-
const goalOptions = [
|
|
87
|
-
{ key: '1', name: 'code_quality', label: 'Code Quality', desc: 'Ship fewer bugs, better tests' },
|
|
88
|
-
{ key: '2', name: 'productivity', label: 'Productivity', desc: 'Complete tasks faster' },
|
|
89
|
-
{ key: '3', name: 'debugging', label: 'Debugging', desc: 'Faster root cause analysis' },
|
|
90
|
-
{ key: '4', name: 'documentation', label: 'Documentation', desc: 'Keep docs up to date' },
|
|
91
|
-
{ key: '5', name: 'automation', label: 'Automation', desc: 'Automate repetitive work' },
|
|
92
|
-
{ key: '6', name: 'learning', label: 'Continuous Learning', desc: 'Stay up to date with tools and patterns' },
|
|
93
|
-
];
|
|
94
|
-
|
|
95
|
-
for (const opt of goalOptions) {
|
|
96
|
-
console.log(` ${opt.key}. ${opt.label} — ${opt.desc}`);
|
|
97
|
-
}
|
|
98
|
-
console.log('');
|
|
99
|
-
|
|
100
|
-
const selectedStr = await ask(' Select areas (enter numbers, e.g. 1,2,5)', '1,2');
|
|
101
|
-
const selectedKeys = selectedStr.split(/[,\s]+/).map(s => s.trim()).filter(Boolean);
|
|
102
|
-
const selectedGoals = goalOptions.filter(o => selectedKeys.includes(o.key));
|
|
103
|
-
if (selectedGoals.length === 0) selectedGoals.push(goalOptions[0], goalOptions[1]);
|
|
104
|
-
|
|
105
|
-
console.log('');
|
|
106
|
-
|
|
107
|
-
const vars = {
|
|
108
|
-
PROJECT_NAME: projectName,
|
|
109
|
-
PROJECT_PURPOSE: purpose
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
// Generate architecture.yaml from selected goals
|
|
113
|
-
function generateArchitecture(goals, rootPurpose) {
|
|
114
|
-
let yaml = `# architecture.yaml — Your goal tree\n`;
|
|
115
|
-
yaml += `# Goals are stable. Implementations evolve.\n`;
|
|
116
|
-
yaml += `# See: https://github.com/JavanC/Homunculus\n\n`;
|
|
117
|
-
yaml += `version: "1.0"\n\n`;
|
|
118
|
-
yaml += `root:\n`;
|
|
119
|
-
yaml += ` purpose: "${rootPurpose}"\n\n`;
|
|
120
|
-
yaml += ` goals:\n`;
|
|
121
|
-
|
|
122
|
-
const goalTemplates = {
|
|
123
|
-
code_quality: {
|
|
124
|
-
purpose: 'Ship fewer bugs, write more maintainable code',
|
|
125
|
-
goals: {
|
|
126
|
-
testing: { purpose: 'Every change has tests', realized_by: '# will evolve' },
|
|
127
|
-
review: { purpose: 'Catch issues before merge', realized_by: '# will evolve' }
|
|
128
|
-
},
|
|
129
|
-
metrics: [{ name: 'test_pass_rate', healthy: '> 90%' }]
|
|
130
|
-
},
|
|
131
|
-
productivity: {
|
|
132
|
-
purpose: 'Complete tasks faster with fewer iterations',
|
|
133
|
-
goals: {
|
|
134
|
-
task_completion: { purpose: 'Finish tasks in fewer cycles', realized_by: '# will evolve' },
|
|
135
|
-
tool_mastery: { purpose: 'Use the right tool on first try', realized_by: '# will evolve' }
|
|
136
|
-
},
|
|
137
|
-
metrics: [{ name: 'avg_iterations_per_task', healthy: 'decreasing trend' }]
|
|
138
|
-
},
|
|
139
|
-
debugging: {
|
|
140
|
-
purpose: 'Find and fix bugs faster',
|
|
141
|
-
goals: {
|
|
142
|
-
root_cause: { purpose: 'Identify root causes, not symptoms', realized_by: '# will evolve' },
|
|
143
|
-
diagnosis_tools: { purpose: 'Use the right debugging approach', realized_by: '# will evolve' }
|
|
144
|
-
},
|
|
145
|
-
metrics: [{ name: 'avg_debug_time', healthy: 'decreasing trend' }]
|
|
146
|
-
},
|
|
147
|
-
documentation: {
|
|
148
|
-
purpose: 'Keep documentation accurate and up to date',
|
|
149
|
-
goals: {
|
|
150
|
-
api_docs: { purpose: 'API docs match implementation', realized_by: '# will evolve' },
|
|
151
|
-
decision_records: { purpose: 'Document why, not just what', realized_by: '# will evolve' }
|
|
152
|
-
},
|
|
153
|
-
metrics: [{ name: 'doc_freshness', healthy: '< 1 week behind code' }]
|
|
154
|
-
},
|
|
155
|
-
automation: {
|
|
156
|
-
purpose: 'Automate repetitive work',
|
|
157
|
-
goals: {
|
|
158
|
-
ci_cd: { purpose: 'Automated build, test, deploy', realized_by: '# will evolve' },
|
|
159
|
-
workflows: { purpose: 'Common sequences as one command', realized_by: '# will evolve' }
|
|
160
|
-
},
|
|
161
|
-
metrics: [{ name: 'manual_steps_per_deploy', healthy: '< 3' }]
|
|
162
|
-
},
|
|
163
|
-
learning: {
|
|
164
|
-
purpose: 'Stay up to date with tools and best practices',
|
|
165
|
-
goals: {
|
|
166
|
-
tool_updates: { purpose: 'Track and adopt useful updates', realized_by: '# will evolve' },
|
|
167
|
-
pattern_discovery: { purpose: 'Find better ways to do things', realized_by: '# will evolve' }
|
|
168
|
-
},
|
|
169
|
-
metrics: [{ name: 'patterns_adopted_per_month', healthy: '> 2' }]
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
for (const goal of goals) {
|
|
174
|
-
const tmpl = goalTemplates[goal.name];
|
|
175
|
-
if (!tmpl) continue;
|
|
176
|
-
yaml += ` ${goal.name}:\n`;
|
|
177
|
-
yaml += ` purpose: "${tmpl.purpose}"\n`;
|
|
178
|
-
if (tmpl.metrics) {
|
|
179
|
-
yaml += ` metrics:\n`;
|
|
180
|
-
for (const m of tmpl.metrics) {
|
|
181
|
-
yaml += ` - name: ${m.name}\n`;
|
|
182
|
-
yaml += ` healthy: "${m.healthy}"\n`;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
if (tmpl.goals) {
|
|
186
|
-
yaml += ` goals:\n`;
|
|
187
|
-
for (const [subName, sub] of Object.entries(tmpl.goals)) {
|
|
188
|
-
yaml += ` ${subName}:\n`;
|
|
189
|
-
yaml += ` purpose: "${sub.purpose}"\n`;
|
|
190
|
-
yaml += ` realized_by: ${sub.realized_by}\n`;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
yaml += `\n`;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
yaml += ` # Add more goals as your system evolves...\n`;
|
|
197
|
-
return yaml;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
42
|
// 1. Create directory structure
|
|
201
43
|
const dirs = [
|
|
202
44
|
'homunculus/instincts/personal',
|
|
@@ -205,6 +47,7 @@ async function main() {
|
|
|
205
47
|
'homunculus/evolved/agents',
|
|
206
48
|
'homunculus/evolved/evals',
|
|
207
49
|
'homunculus/experiments',
|
|
50
|
+
'homunculus/reports',
|
|
208
51
|
'scripts',
|
|
209
52
|
'.claude/rules',
|
|
210
53
|
'.claude/commands'
|
|
@@ -215,51 +58,37 @@ async function main() {
|
|
|
215
58
|
}
|
|
216
59
|
console.log(' \x1b[32m✓\x1b[0m Created homunculus/ directory structure');
|
|
217
60
|
|
|
218
|
-
// 2.
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
fs.
|
|
223
|
-
console.log(
|
|
224
|
-
} else {
|
|
225
|
-
console.log(' \x1b[33m-\x1b[0m architecture.yaml already exists, skipping');
|
|
61
|
+
// 2. Copy evolution rules
|
|
62
|
+
const rulesSrc = path.join(TEMPLATES_DIR, 'rules', 'evolution-system.md');
|
|
63
|
+
const rulesDest = path.join(projectDir, '.claude', 'rules', 'evolution-system.md');
|
|
64
|
+
if (!fs.existsSync(rulesDest) && fs.existsSync(rulesSrc)) {
|
|
65
|
+
fs.copyFileSync(rulesSrc, rulesDest);
|
|
66
|
+
console.log(' \x1b[32m✓\x1b[0m Added evolution rules');
|
|
226
67
|
}
|
|
227
68
|
|
|
228
|
-
// 3. Copy CLAUDE.md template
|
|
69
|
+
// 3. Copy CLAUDE.md template
|
|
70
|
+
const claudeSrc = path.join(TEMPLATES_DIR, 'CLAUDE.md.template');
|
|
229
71
|
const claudeDest = path.join(projectDir, 'CLAUDE.md');
|
|
230
|
-
if (!fs.existsSync(claudeDest)) {
|
|
231
|
-
const template = fs.readFileSync(
|
|
232
|
-
|
|
233
|
-
);
|
|
234
|
-
fs.writeFileSync(claudeDest, replaceTemplateVars(template, vars));
|
|
72
|
+
if (!fs.existsSync(claudeDest) && fs.existsSync(claudeSrc)) {
|
|
73
|
+
const template = fs.readFileSync(claudeSrc, 'utf8');
|
|
74
|
+
const projectName = path.basename(projectDir);
|
|
75
|
+
fs.writeFileSync(claudeDest, template.replace(/\{\{PROJECT_NAME\}\}/g, projectName));
|
|
235
76
|
console.log(' \x1b[32m✓\x1b[0m Created CLAUDE.md');
|
|
236
|
-
} else {
|
|
237
|
-
console.log(' \x1b[33m-\x1b[0m CLAUDE.md already exists, skipping');
|
|
238
77
|
}
|
|
239
78
|
|
|
240
|
-
// 4. Copy
|
|
241
|
-
const rulesDest = path.join(projectDir, '.claude', 'rules', 'evolution-system.md');
|
|
242
|
-
if (!fs.existsSync(rulesDest)) {
|
|
243
|
-
copyFile(
|
|
244
|
-
path.join(TEMPLATES_DIR, 'rules', 'evolution-system.md'),
|
|
245
|
-
rulesDest
|
|
246
|
-
);
|
|
247
|
-
console.log(' \x1b[32m✓\x1b[0m Created .claude/rules/evolution-system.md');
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// 5. Copy core scripts
|
|
79
|
+
// 4. Copy core scripts
|
|
251
80
|
if (fs.existsSync(CORE_DIR)) {
|
|
252
81
|
copyDir(CORE_DIR, path.join(projectDir, 'scripts'));
|
|
253
|
-
console.log(' \x1b[32m✓\x1b[0m Copied evolution scripts
|
|
82
|
+
console.log(' \x1b[32m✓\x1b[0m Copied evolution scripts');
|
|
254
83
|
}
|
|
255
84
|
|
|
256
|
-
//
|
|
85
|
+
// 5. Copy slash commands
|
|
257
86
|
if (fs.existsSync(COMMANDS_DIR)) {
|
|
258
87
|
copyDir(COMMANDS_DIR, path.join(projectDir, '.claude', 'commands'));
|
|
259
|
-
console.log(' \x1b[32m✓\x1b[0m
|
|
88
|
+
console.log(' \x1b[32m✓\x1b[0m Added slash commands (/hm-setup, /hm-night, /hm-status)');
|
|
260
89
|
}
|
|
261
90
|
|
|
262
|
-
//
|
|
91
|
+
// 6. Configure Claude Code hooks
|
|
263
92
|
const settingsPath = path.join(projectDir, '.claude', 'settings.json');
|
|
264
93
|
let settings = {};
|
|
265
94
|
if (fs.existsSync(settingsPath)) {
|
|
@@ -275,10 +104,10 @@ async function main() {
|
|
|
275
104
|
}];
|
|
276
105
|
ensureDir(path.join(projectDir, '.claude'));
|
|
277
106
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
278
|
-
console.log(' \x1b[32m✓\x1b[0m Configured
|
|
107
|
+
console.log(' \x1b[32m✓\x1b[0m Configured observation hook');
|
|
279
108
|
}
|
|
280
109
|
|
|
281
|
-
//
|
|
110
|
+
// 7. Create .gitignore additions
|
|
282
111
|
const gitignorePath = path.join(projectDir, '.gitignore');
|
|
283
112
|
const gitignoreEntries = [
|
|
284
113
|
'',
|
|
@@ -299,19 +128,15 @@ async function main() {
|
|
|
299
128
|
console.log(' \x1b[32m✓\x1b[0m Created .gitignore');
|
|
300
129
|
}
|
|
301
130
|
|
|
131
|
+
// Done
|
|
302
132
|
console.log('');
|
|
303
|
-
console.log(' \x1b[1m\x1b[32mDone!\x1b[0m
|
|
133
|
+
console.log(' \x1b[1m\x1b[32mDone!\x1b[0m Homunculus is installed.');
|
|
304
134
|
console.log('');
|
|
305
135
|
console.log(' Next steps:');
|
|
306
|
-
console.log('
|
|
307
|
-
console.log('
|
|
308
|
-
console.log('
|
|
136
|
+
console.log(' 1. Run \x1b[1mclaude\x1b[0m to open Claude Code');
|
|
137
|
+
console.log(' 2. Type \x1b[1m/hm-setup\x1b[0m to define your goals (AI-guided)');
|
|
138
|
+
console.log(' 3. Type \x1b[1m/hm-night\x1b[0m to run your first evolution cycle');
|
|
309
139
|
console.log('');
|
|
310
|
-
|
|
311
|
-
if (rl) rl.close();
|
|
312
140
|
}
|
|
313
141
|
|
|
314
|
-
main()
|
|
315
|
-
console.error('Error:', err.message);
|
|
316
|
-
process.exit(1);
|
|
317
|
-
});
|
|
142
|
+
main();
|