homunculus-code 0.1.0 → 0.2.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 +38 -7
- package/bin/cli.js +36 -0
- package/bin/night.js +292 -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)
|
|
@@ -169,20 +170,50 @@ The wizard asks you a few questions and sets everything up:
|
|
|
169
170
|
Done! Start using Claude Code. Your assistant will evolve.
|
|
170
171
|
```
|
|
171
172
|
|
|
172
|
-
### 2.
|
|
173
|
+
### 2. Run Your First Evolution Cycle
|
|
173
174
|
|
|
174
|
-
|
|
175
|
+
```bash
|
|
176
|
+
npx homunculus-code night
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Watch the system check your goals, scan for patterns, and generate a report:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
🌙 Homunculus — Evolution Cycle
|
|
183
|
+
|
|
184
|
+
[1/5] Health Check
|
|
185
|
+
code_quality: ○ no data yet
|
|
186
|
+
productivity: ○ no data yet
|
|
187
|
+
|
|
188
|
+
[2/5] Scan Instincts
|
|
189
|
+
○ No instincts yet — use Claude Code normally, patterns will emerge
|
|
190
|
+
|
|
191
|
+
[3/5] Eval Skills
|
|
192
|
+
○ No skills yet — instincts converge into skills over time
|
|
193
|
+
|
|
194
|
+
[4/5] Research
|
|
195
|
+
✓ Claude Code 2.1.81
|
|
196
|
+
△ 0/7 goals have health checks — add more for better evolution
|
|
197
|
+
|
|
198
|
+
[5/5] Report
|
|
199
|
+
┌────────────────────────────────────────────┐
|
|
200
|
+
│ Evolution Report — 2026-03-22 │
|
|
201
|
+
│ Goals: 7 | Instincts: 0 | Skills: 0 │
|
|
202
|
+
│ Status: Fresh install — ready to evolve │
|
|
203
|
+
└────────────────────────────────────────────┘
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### 3. Use Claude Code Normally
|
|
207
|
+
|
|
208
|
+
The observation hook watches your usage automatically. As patterns emerge, run `night` again to see your system evolve. Or set up the [nightly agent](docs/nightly-agent.md) to do it autonomously while you sleep.
|
|
175
209
|
|
|
176
210
|
```bash
|
|
177
|
-
|
|
211
|
+
npx homunculus-code night # Manual evolution cycle
|
|
212
|
+
claude "/eval-skill" # Evaluate a specific skill
|
|
178
213
|
claude "/improve-skill" # Auto-improve a skill
|
|
179
214
|
claude "/evolve" # Converge instincts into skills
|
|
180
215
|
```
|
|
181
216
|
|
|
182
|
-
### 3. Refine Your Goals (Optional)
|
|
183
|
-
|
|
184
|
-
As you use the system, refine `architecture.yaml` — add sub-goals, metrics, and health checks. The more specific your goals, the smarter the evolution.
|
|
185
|
-
|
|
186
217
|
---
|
|
187
218
|
|
|
188
219
|
## Key Concepts
|
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/night.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// homunculus night — Run one evolution cycle
|
|
3
|
+
// Simulates what the nightly agent does: health check → evolve → research → report
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
const projectDir = process.cwd();
|
|
10
|
+
const HOMUNCULUS_DIR = path.join(projectDir, 'homunculus');
|
|
11
|
+
const ARCH_FILE = path.join(projectDir, 'architecture.yaml');
|
|
12
|
+
const INSTINCTS_DIR = path.join(HOMUNCULUS_DIR, 'instincts', 'personal');
|
|
13
|
+
const ARCHIVED_DIR = path.join(HOMUNCULUS_DIR, 'instincts', 'archived');
|
|
14
|
+
const SKILLS_DIR = path.join(HOMUNCULUS_DIR, 'evolved', 'skills');
|
|
15
|
+
const EVALS_DIR = path.join(HOMUNCULUS_DIR, 'evolved', 'evals');
|
|
16
|
+
const OBS_FILE = path.join(HOMUNCULUS_DIR, 'observations.jsonl');
|
|
17
|
+
const SCRIPTS_DIR = path.join(projectDir, 'scripts');
|
|
18
|
+
|
|
19
|
+
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
20
|
+
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
21
|
+
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
22
|
+
const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
|
|
23
|
+
const red = (s) => `\x1b[31m${s}\x1b[0m`;
|
|
24
|
+
const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
|
|
25
|
+
|
|
26
|
+
function countFiles(dir, ext = '.md') {
|
|
27
|
+
try {
|
|
28
|
+
return fs.readdirSync(dir).filter(f => f.endsWith(ext)).length;
|
|
29
|
+
} catch { return 0; }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function countLines(file) {
|
|
33
|
+
try {
|
|
34
|
+
return fs.readFileSync(file, 'utf8').trim().split('\n').filter(Boolean).length;
|
|
35
|
+
} catch { return 0; }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function sleep(ms) {
|
|
39
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseGoals(yamlContent) {
|
|
43
|
+
const goals = [];
|
|
44
|
+
const lines = yamlContent.split('\n');
|
|
45
|
+
let currentGoal = null;
|
|
46
|
+
let indent = 0;
|
|
47
|
+
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
// Match top-level goals (direct children of "goals:")
|
|
50
|
+
const goalMatch = line.match(/^ (\w+):$/);
|
|
51
|
+
if (goalMatch && !line.includes('purpose') && !line.includes('metrics') &&
|
|
52
|
+
!line.includes('health_check') && !line.includes('realized_by') &&
|
|
53
|
+
!line.includes('goals:') && !line.includes('command') &&
|
|
54
|
+
!line.includes('expected') && !line.includes('healthy') &&
|
|
55
|
+
!line.includes('name:') && !line.includes('source')) {
|
|
56
|
+
currentGoal = goalMatch[1];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const purposeMatch = line.match(/purpose:\s*"(.+)"/);
|
|
60
|
+
if (purposeMatch && currentGoal) {
|
|
61
|
+
goals.push({ name: currentGoal, purpose: purposeMatch[1] });
|
|
62
|
+
currentGoal = null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return goals;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function main() {
|
|
69
|
+
console.log('');
|
|
70
|
+
console.log(` ${bold('🌙 Homunculus — Evolution Cycle')}`);
|
|
71
|
+
console.log(` ${dim(new Date().toISOString().replace('T', ' ').slice(0, 19))}`);
|
|
72
|
+
console.log('');
|
|
73
|
+
|
|
74
|
+
// Check if initialized
|
|
75
|
+
if (!fs.existsSync(HOMUNCULUS_DIR)) {
|
|
76
|
+
console.log(` ${red('✗')} Not initialized. Run ${bold('npx homunculus-code init')} first.`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ─────────────────────────────────────────
|
|
81
|
+
// Phase 1: Health Check
|
|
82
|
+
// ─────────────────────────────────────────
|
|
83
|
+
console.log(` ${bold('[1/5] Health Check')}`);
|
|
84
|
+
await sleep(300);
|
|
85
|
+
|
|
86
|
+
if (fs.existsSync(ARCH_FILE)) {
|
|
87
|
+
const yaml = fs.readFileSync(ARCH_FILE, 'utf8');
|
|
88
|
+
const goals = parseGoals(yaml);
|
|
89
|
+
|
|
90
|
+
if (goals.length > 0) {
|
|
91
|
+
for (const goal of goals) {
|
|
92
|
+
// Simple heuristic: if realized_by exists and points to real file = healthy
|
|
93
|
+
const status = yellow('○ no data yet');
|
|
94
|
+
console.log(` ${goal.name}: ${status}`);
|
|
95
|
+
console.log(` ${dim(goal.purpose)}`);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
console.log(` ${yellow('○')} No goals defined in architecture.yaml`);
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
console.log(` ${red('✗')} architecture.yaml not found`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.log('');
|
|
105
|
+
await sleep(200);
|
|
106
|
+
|
|
107
|
+
// ─────────────────────────────────────────
|
|
108
|
+
// Phase 2: Scan Instincts
|
|
109
|
+
// ─────────────────────────────────────────
|
|
110
|
+
console.log(` ${bold('[2/5] Scan Instincts')}`);
|
|
111
|
+
await sleep(300);
|
|
112
|
+
|
|
113
|
+
const activeInstincts = countFiles(INSTINCTS_DIR);
|
|
114
|
+
const archivedInstincts = countFiles(ARCHIVED_DIR);
|
|
115
|
+
const observations = countLines(OBS_FILE);
|
|
116
|
+
|
|
117
|
+
if (activeInstincts > 0) {
|
|
118
|
+
console.log(` ${green('✓')} ${activeInstincts} active instincts (${archivedInstincts} archived)`);
|
|
119
|
+
|
|
120
|
+
// Run prune check
|
|
121
|
+
try {
|
|
122
|
+
const pruneScript = path.join(SCRIPTS_DIR, 'prune-instincts.js');
|
|
123
|
+
if (fs.existsSync(pruneScript)) {
|
|
124
|
+
const result = execSync(`node "${pruneScript}"`, {
|
|
125
|
+
encoding: 'utf8', timeout: 10000, cwd: projectDir
|
|
126
|
+
});
|
|
127
|
+
const candidateMatch = result.match(/Candidates:\s*(\d+)/);
|
|
128
|
+
if (candidateMatch && parseInt(candidateMatch[1]) > 0) {
|
|
129
|
+
console.log(` ${yellow('△')} ${candidateMatch[1]} instincts eligible for archival`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} catch {}
|
|
133
|
+
} else if (observations > 0) {
|
|
134
|
+
console.log(` ${yellow('○')} ${observations} observations recorded, no instincts extracted yet`);
|
|
135
|
+
console.log(` ${dim('Tip: instincts are extracted at session end when enough patterns emerge')}`);
|
|
136
|
+
} else {
|
|
137
|
+
console.log(` ${yellow('○')} No instincts yet — use Claude Code normally, patterns will emerge`);
|
|
138
|
+
console.log(` ${dim('The observation hook is watching. Keep using Claude Code.')}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log('');
|
|
142
|
+
await sleep(200);
|
|
143
|
+
|
|
144
|
+
// ─────────────────────────────────────────
|
|
145
|
+
// Phase 3: Eval Skills
|
|
146
|
+
// ─────────────────────────────────────────
|
|
147
|
+
console.log(` ${bold('[3/5] Eval Skills')}`);
|
|
148
|
+
await sleep(300);
|
|
149
|
+
|
|
150
|
+
const skillCount = countFiles(SKILLS_DIR);
|
|
151
|
+
const evalCount = countFiles(EVALS_DIR, '.yaml');
|
|
152
|
+
|
|
153
|
+
if (skillCount > 0) {
|
|
154
|
+
console.log(` ${green('✓')} ${skillCount} evolved skills found`);
|
|
155
|
+
|
|
156
|
+
// List skills
|
|
157
|
+
try {
|
|
158
|
+
const skills = fs.readdirSync(SKILLS_DIR).filter(f => f.endsWith('.md'));
|
|
159
|
+
for (const skill of skills) {
|
|
160
|
+
const name = skill.replace('.md', '');
|
|
161
|
+
const hasEval = fs.existsSync(path.join(EVALS_DIR, `${name}.eval.yaml`));
|
|
162
|
+
if (hasEval) {
|
|
163
|
+
console.log(` ${green('✓')} ${name} — has eval spec`);
|
|
164
|
+
} else {
|
|
165
|
+
console.log(` ${yellow('○')} ${name} — no eval spec yet`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
} catch {}
|
|
169
|
+
|
|
170
|
+
if (evalCount > 0) {
|
|
171
|
+
console.log(` ${dim(`Run 'claude "/eval-skill"' to evaluate, or let the nightly agent handle it`)}`);
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
console.log(` ${yellow('○')} No skills yet — instincts converge into skills over time`);
|
|
175
|
+
console.log(` ${dim(`Once you have 3+ related instincts, run 'claude "/evolve"'`)}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
console.log('');
|
|
179
|
+
await sleep(200);
|
|
180
|
+
|
|
181
|
+
// ─────────────────────────────────────────
|
|
182
|
+
// Phase 4: Research
|
|
183
|
+
// ─────────────────────────────────────────
|
|
184
|
+
console.log(` ${bold('[4/5] Research')}`);
|
|
185
|
+
await sleep(300);
|
|
186
|
+
|
|
187
|
+
// Check Claude Code version
|
|
188
|
+
try {
|
|
189
|
+
const version = execSync('claude --version 2>/dev/null', {
|
|
190
|
+
encoding: 'utf8', timeout: 5000
|
|
191
|
+
}).trim();
|
|
192
|
+
console.log(` ${green('✓')} Claude Code ${version}`);
|
|
193
|
+
} catch {
|
|
194
|
+
console.log(` ${yellow('○')} Claude Code version check skipped`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Check Node version
|
|
198
|
+
const nodeVersion = process.version;
|
|
199
|
+
console.log(` ${green('✓')} Node.js ${nodeVersion}`);
|
|
200
|
+
|
|
201
|
+
// Check architecture health
|
|
202
|
+
if (fs.existsSync(ARCH_FILE)) {
|
|
203
|
+
const yaml = fs.readFileSync(ARCH_FILE, 'utf8');
|
|
204
|
+
const goalCount = (yaml.match(/purpose:/g) || []).length;
|
|
205
|
+
const healthChecks = (yaml.match(/health_check:/g) || []).length;
|
|
206
|
+
const realizedBy = (yaml.match(/realized_by:/g) || []).length;
|
|
207
|
+
|
|
208
|
+
if (healthChecks < goalCount / 2) {
|
|
209
|
+
console.log(` ${yellow('△')} ${healthChecks}/${goalCount} goals have health checks — add more for better evolution`);
|
|
210
|
+
}
|
|
211
|
+
if (realizedBy < goalCount / 2) {
|
|
212
|
+
console.log(` ${yellow('△')} ${realizedBy}/${goalCount} goals have implementations — some are waiting to evolve`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
console.log('');
|
|
217
|
+
await sleep(200);
|
|
218
|
+
|
|
219
|
+
// ─────────────────────────────────────────
|
|
220
|
+
// Phase 5: Report
|
|
221
|
+
// ─────────────────────────────────────────
|
|
222
|
+
console.log(` ${bold('[5/5] Report')}`);
|
|
223
|
+
await sleep(300);
|
|
224
|
+
|
|
225
|
+
const reportDate = new Date().toISOString().slice(0, 10);
|
|
226
|
+
const reportLines = [];
|
|
227
|
+
|
|
228
|
+
console.log('');
|
|
229
|
+
console.log(` ┌${'─'.repeat(52)}┐`);
|
|
230
|
+
console.log(` │ ${bold(` Evolution Report — ${reportDate}`)} │`);
|
|
231
|
+
console.log(` ├${'─'.repeat(52)}┤`);
|
|
232
|
+
|
|
233
|
+
// Summary
|
|
234
|
+
const goalCount = fs.existsSync(ARCH_FILE)
|
|
235
|
+
? (fs.readFileSync(ARCH_FILE, 'utf8').match(/purpose:/g) || []).length
|
|
236
|
+
: 0;
|
|
237
|
+
|
|
238
|
+
console.log(` │ │`);
|
|
239
|
+
console.log(` │ ${cyan('Goals:')} ${String(goalCount).padStart(3)} │`);
|
|
240
|
+
console.log(` │ ${cyan('Instincts:')} ${String(activeInstincts).padStart(3)} active / ${String(archivedInstincts).padStart(3)} archived │`);
|
|
241
|
+
console.log(` │ ${cyan('Skills:')} ${String(skillCount).padStart(3)} (${evalCount} with eval specs) │`);
|
|
242
|
+
console.log(` │ ${cyan('Observations:')} ${String(observations).padStart(5)} │`);
|
|
243
|
+
console.log(` │ │`);
|
|
244
|
+
|
|
245
|
+
if (activeInstincts === 0 && skillCount === 0) {
|
|
246
|
+
console.log(` │ ${bold('Status:')} Fresh install — ready to evolve │`);
|
|
247
|
+
console.log(` │ │`);
|
|
248
|
+
console.log(` │ ${dim('Next steps:')} │`);
|
|
249
|
+
console.log(` │ ${dim('1. Use Claude Code on your project')} │`);
|
|
250
|
+
console.log(` │ ${dim('2. Patterns will be auto-extracted')} │`);
|
|
251
|
+
console.log(` │ ${dim('3. Run this command again to see progress')} │`);
|
|
252
|
+
} else if (skillCount === 0) {
|
|
253
|
+
console.log(` │ ${bold('Status:')} Collecting patterns... │`);
|
|
254
|
+
console.log(` │ │`);
|
|
255
|
+
console.log(` │ ${dim('You have instincts! When 3+ are related,')} │`);
|
|
256
|
+
console.log(` │ ${dim('run claude "/evolve" to create your first skill.')} │`);
|
|
257
|
+
} else {
|
|
258
|
+
console.log(` │ ${bold('Status:')} ${green('Evolving')} │`);
|
|
259
|
+
console.log(` │ │`);
|
|
260
|
+
console.log(` │ ${dim('Run claude "/eval-skill" to check quality,')} │`);
|
|
261
|
+
console.log(` │ ${dim('or set up the nightly agent for autonomy.')} │`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
console.log(` │ │`);
|
|
265
|
+
console.log(` └${'─'.repeat(52)}┘`);
|
|
266
|
+
console.log('');
|
|
267
|
+
|
|
268
|
+
// Save report to file
|
|
269
|
+
const reportDir = path.join(HOMUNCULUS_DIR, 'reports');
|
|
270
|
+
if (!fs.existsSync(reportDir)) fs.mkdirSync(reportDir, { recursive: true });
|
|
271
|
+
|
|
272
|
+
const reportContent = [
|
|
273
|
+
`# Evolution Report — ${reportDate}`,
|
|
274
|
+
'',
|
|
275
|
+
'## Summary',
|
|
276
|
+
`- Goals: ${goalCount}`,
|
|
277
|
+
`- Instincts: ${activeInstincts} active / ${archivedInstincts} archived`,
|
|
278
|
+
`- Skills: ${skillCount} (${evalCount} with eval specs)`,
|
|
279
|
+
`- Observations: ${observations}`,
|
|
280
|
+
'',
|
|
281
|
+
`Generated by \`npx homunculus-code night\``,
|
|
282
|
+
].join('\n');
|
|
283
|
+
|
|
284
|
+
fs.writeFileSync(path.join(reportDir, `${reportDate}.md`), reportContent + '\n');
|
|
285
|
+
console.log(` ${dim(`Report saved to homunculus/reports/${reportDate}.md`)}`);
|
|
286
|
+
console.log('');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
main().catch(err => {
|
|
290
|
+
console.error('Error:', err.message);
|
|
291
|
+
process.exit(1);
|
|
292
|
+
});
|
|
@@ -10,7 +10,19 @@ reference/
|
|
|
10
10
|
├── evolved-skills/ # 7 evolved skills (all 100% eval pass)
|
|
11
11
|
│ ├── api-system-diagnosis.md
|
|
12
12
|
│ ├── assistant-system-management.md
|
|
13
|
-
│ ├── claude-code-reference
|
|
13
|
+
│ ├── claude-code-reference/ # Split into index + 11 chapters (95% context reduction)
|
|
14
|
+
│ │ ├── index.md # Routing table — loads chapters on demand
|
|
15
|
+
│ │ ├── ch01-extensions.md
|
|
16
|
+
│ │ ├── ch02-agents.md
|
|
17
|
+
│ │ ├── ch03-hooks.md
|
|
18
|
+
│ │ ├── ch04-mcp.md
|
|
19
|
+
│ │ ├── ch05-ui.md
|
|
20
|
+
│ │ ├── ch06-rules-security.md
|
|
21
|
+
│ │ ├── ch07-model-memory.md
|
|
22
|
+
│ │ ├── ch08-workflows.md
|
|
23
|
+
│ │ ├── ch09-integrations.md
|
|
24
|
+
│ │ ├── ch10-cli-sdk.md
|
|
25
|
+
│ │ └── ch11-output-versions.md
|
|
14
26
|
│ ├── development-verification-patterns.md
|
|
15
27
|
│ ├── multi-agent-design-patterns.md
|
|
16
28
|
│ ├── shell-automation-patterns.md
|