groove-dev 0.27.175 → 0.27.179
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/AUTONOMOUS_AGENT_FRAMEWORK.md +654 -0
- package/innerchat/Screenshot_2026-06-09_at_2.19.42_PM.png +0 -0
- package/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/api.js +3 -1
- package/node_modules/@groove-dev/daemon/src/autostate.js +198 -0
- package/node_modules/@groove-dev/daemon/src/index.js +6 -0
- package/node_modules/@groove-dev/daemon/src/orchestrator.js +585 -0
- package/node_modules/@groove-dev/daemon/src/process.js +27 -2
- package/node_modules/@groove-dev/daemon/src/registry.js +2 -1
- package/node_modules/@groove-dev/daemon/src/routes/auto-agents.js +264 -0
- package/node_modules/@groove-dev/daemon/src/validate.js +6 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-CTer01Vg.js +1065 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-DTFtRtkx.css +1 -0
- package/node_modules/@groove-dev/gui/dist/index.html +2 -2
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/App.jsx +2 -0
- package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +53 -0
- package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +95 -2
- package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +50 -1
- package/node_modules/@groove-dev/gui/src/components/auto-agents/auto-agent-card.jsx +139 -0
- package/node_modules/@groove-dev/gui/src/components/auto-agents/auto-agent-detail.jsx +286 -0
- package/node_modules/@groove-dev/gui/src/components/auto-agents/setup-wizard.jsx +284 -0
- package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +2 -1
- package/node_modules/@groove-dev/gui/src/stores/groove.js +14 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/auto-agents-slice.js +149 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/ui-slice.js +14 -2
- package/node_modules/@groove-dev/gui/src/views/auto-agents.jsx +70 -0
- package/node_modules/@groove-dev/gui/src/views/settings.jsx +13 -6
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +3 -1
- package/packages/daemon/src/autostate.js +198 -0
- package/packages/daemon/src/index.js +6 -0
- package/packages/daemon/src/orchestrator.js +585 -0
- package/packages/daemon/src/process.js +27 -2
- package/packages/daemon/src/registry.js +2 -1
- package/packages/daemon/src/routes/auto-agents.js +264 -0
- package/packages/daemon/src/validate.js +6 -0
- package/packages/gui/dist/assets/index-CTer01Vg.js +1065 -0
- package/packages/gui/dist/assets/index-DTFtRtkx.css +1 -0
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/App.jsx +2 -0
- package/packages/gui/src/components/agents/agent-config.jsx +53 -0
- package/packages/gui/src/components/agents/agent-panel.jsx +95 -2
- package/packages/gui/src/components/agents/spawn-wizard.jsx +50 -1
- package/packages/gui/src/components/auto-agents/auto-agent-card.jsx +139 -0
- package/packages/gui/src/components/auto-agents/auto-agent-detail.jsx +286 -0
- package/packages/gui/src/components/auto-agents/setup-wizard.jsx +284 -0
- package/packages/gui/src/components/layout/activity-bar.jsx +2 -1
- package/packages/gui/src/stores/groove.js +14 -0
- package/packages/gui/src/stores/slices/auto-agents-slice.js +149 -0
- package/packages/gui/src/stores/slices/ui-slice.js +14 -2
- package/packages/gui/src/views/auto-agents.jsx +70 -0
- package/packages/gui/src/views/settings.jsx +13 -6
- package/node_modules/@groove-dev/gui/dist/assets/index-BMaxZVeX.js +0 -1035
- package/node_modules/@groove-dev/gui/dist/assets/index-BvJwMNAX.css +0 -1
- package/packages/gui/dist/assets/index-BMaxZVeX.js +0 -1035
- package/packages/gui/dist/assets/index-BvJwMNAX.css +0 -1
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
# Autonomous Claude Agent Framework — Build Plan
|
|
2
|
+
|
|
3
|
+
A general-purpose framework for deploying Claude Code as an autonomous employee that
|
|
4
|
+
runs 24/7, iterates on complex multi-step tasks, learns from failures, and communicates
|
|
5
|
+
progress — without human intervention between cycles.
|
|
6
|
+
|
|
7
|
+
Built and validated on the GRAFT MoE training pipeline (10+ autonomous cycles, code
|
|
8
|
+
modifications, experiment design, failure analysis, and creative problem-solving).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Architecture Overview
|
|
13
|
+
|
|
14
|
+
Five components working together:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
┌─────────────┐ cron ┌──────────────┐ spawns ┌───────────┐
|
|
18
|
+
│ Crontab │ ──────────> │ Orchestrator │ ──────────> │ Claude CLI│
|
|
19
|
+
│ (heartbeat)│ │ (Python) │ │ (decision │
|
|
20
|
+
└─────────────┘ └──────┬───────┘ │ maker) │
|
|
21
|
+
│ └─────┬─────┘
|
|
22
|
+
reads/writes │
|
|
23
|
+
│ reads/writes/
|
|
24
|
+
v executes
|
|
25
|
+
┌──────────────┐ │
|
|
26
|
+
│ State Layer │ <─────────────────┘
|
|
27
|
+
│ │
|
|
28
|
+
│ - state.json │ ┌───────────────┐
|
|
29
|
+
│ - journal │ │ Work Layer │
|
|
30
|
+
│ - roadmap │ │ │
|
|
31
|
+
│ - prompt │ │ - scripts │
|
|
32
|
+
│ - CLAUDE.md │ │ - outputs │
|
|
33
|
+
└──────────────┘ │ - logs │
|
|
34
|
+
│ - email │
|
|
35
|
+
└───────────────┘
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Human communicates IN** by editing state files (prompt, roadmap, state.json).
|
|
39
|
+
**Agent communicates OUT** via email, logs, and state file updates.
|
|
40
|
+
No blocking. No polling. No awaiting approval. Fire and forget.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Component 1: The Orchestrator
|
|
45
|
+
|
|
46
|
+
**What it is:** A Python script triggered by cron. It does NOT make decisions — it checks
|
|
47
|
+
status, detects transitions, and hands off to Claude when something needs a decision.
|
|
48
|
+
|
|
49
|
+
**Core logic (pseudocode):**
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
def main():
|
|
53
|
+
state = load_state()
|
|
54
|
+
phase = state["phase"]
|
|
55
|
+
|
|
56
|
+
# 1. Is something actively running?
|
|
57
|
+
if is_anything_running():
|
|
58
|
+
log_path = get_active_log(state, phase)
|
|
59
|
+
report_progress(phase, log_path)
|
|
60
|
+
|
|
61
|
+
# Stale process detection
|
|
62
|
+
if log_is_stale(log_path, max_age_hours=4):
|
|
63
|
+
handoff_to_claude("Process stuck — log stale for 4+ hours")
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
# 2. Nothing running — a transition happened. Hand off to Claude.
|
|
67
|
+
situation = detect_situation(state, phase) # completed / failed / idle
|
|
68
|
+
handoff_to_claude(situation)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Key design decisions:**
|
|
72
|
+
|
|
73
|
+
- **Orchestrator is dumb, Claude is smart.** The orchestrator is a ~200-line state machine
|
|
74
|
+
that detects "something changed" and calls Claude. All intelligence lives in the prompt.
|
|
75
|
+
This means you can change Claude's behavior entirely by editing the prompt file — no code
|
|
76
|
+
deploys needed.
|
|
77
|
+
|
|
78
|
+
- **Stale process detection.** Long-running jobs (training, builds, deploys) write to log
|
|
79
|
+
files. If the log hasn't been updated in N hours, the process is stuck. The orchestrator
|
|
80
|
+
detects this and hands off to Claude to diagnose and fix it.
|
|
81
|
+
|
|
82
|
+
- **Graceful degradation.** If Claude CLI fails (timeout, API error), the orchestrator can
|
|
83
|
+
fall back to rule-based handlers for known phases. Optional but useful for critical paths.
|
|
84
|
+
|
|
85
|
+
### The Handoff Function
|
|
86
|
+
|
|
87
|
+
The most important function in the orchestrator:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
def handoff_to_claude(situation):
|
|
91
|
+
state = load_state()
|
|
92
|
+
journal = load_journal()
|
|
93
|
+
|
|
94
|
+
prompt = f"""
|
|
95
|
+
{read_file("system_prompt.md")} # Identity, tools, rules, philosophy
|
|
96
|
+
|
|
97
|
+
## Current Situation
|
|
98
|
+
{situation} # What just happened
|
|
99
|
+
|
|
100
|
+
## Full Context
|
|
101
|
+
{build_context_summary(journal, state)} # History, findings, current settings
|
|
102
|
+
|
|
103
|
+
## Recent Log Output
|
|
104
|
+
{tail_log(get_active_log(state), 60)} # Last 60 lines of relevant log
|
|
105
|
+
|
|
106
|
+
Take ownership. Analyze, decide, and execute.
|
|
107
|
+
Update state and journal with your decisions.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
result = subprocess.run(
|
|
111
|
+
["claude", "-p", "--dangerously-skip-permissions", "--output-format", "text"],
|
|
112
|
+
input=prompt,
|
|
113
|
+
capture_output=True, text=True,
|
|
114
|
+
timeout=600, # 10 min max per handoff
|
|
115
|
+
cwd=PROJECT_DIR,
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Critical:** `--dangerously-skip-permissions` is required for autonomous operation.
|
|
120
|
+
Claude needs to run commands, edit files, and launch processes without approval prompts.
|
|
121
|
+
|
|
122
|
+
### Orchestrator Robustness
|
|
123
|
+
|
|
124
|
+
Things Claude WILL do that break naive orchestrators:
|
|
125
|
+
|
|
126
|
+
- **Write non-dict values to state fields.** Claude might set `current_run` to a string
|
|
127
|
+
instead of a dict, or to `null`. Always use defensive accessors:
|
|
128
|
+
```python
|
|
129
|
+
def safe_dict(state, key):
|
|
130
|
+
v = state.get(key)
|
|
131
|
+
return v if isinstance(v, dict) else {}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
- **Set unexpected phase names.** Claude will invent phases like `"awaiting_decision"` or
|
|
135
|
+
`"levers_exhausted"`. Your orchestrator should handle unknown phases gracefully (hand off
|
|
136
|
+
to Claude again rather than crash).
|
|
137
|
+
|
|
138
|
+
- **Write verbose essays into state fields.** Phase notes may be 500+ characters. Don't
|
|
139
|
+
assume they're short. Don't use them as dict keys.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Component 2: The State Layer
|
|
144
|
+
|
|
145
|
+
Five files that together give Claude full context every invocation. Claude has no memory
|
|
146
|
+
between cron ticks — these files ARE its memory.
|
|
147
|
+
|
|
148
|
+
### 2a. State File (state.json)
|
|
149
|
+
|
|
150
|
+
The real-time status of the agent. Updated every invocation by both orchestrator and Claude.
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"phase": "training-cycle-3",
|
|
155
|
+
"phase_note": "Training on mixed dataset, lr=5e-5, 5000 steps",
|
|
156
|
+
"cycle": 3,
|
|
157
|
+
"current_run": {
|
|
158
|
+
"pid": 12345,
|
|
159
|
+
"settings": {"lr": "5e-5", "steps": 5000, "data": "mixed_316k.jsonl"},
|
|
160
|
+
"started": "2026-06-27T14:00:00"
|
|
161
|
+
},
|
|
162
|
+
"champion": {
|
|
163
|
+
"tag": "cycle2-best",
|
|
164
|
+
"score": 85.3,
|
|
165
|
+
"backups": ["model.safetensors.cycle2_best"]
|
|
166
|
+
},
|
|
167
|
+
"history": [
|
|
168
|
+
{"tag": "cycle1", "score": 78.2, "note": "baseline"},
|
|
169
|
+
{"tag": "cycle2", "score": 85.3, "note": "new best, lr=3e-5"}
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Design principles:**
|
|
175
|
+
- One file, flat structure, human-readable
|
|
176
|
+
- History array preserves every result — Claude uses this to avoid repeating failures
|
|
177
|
+
- Champion section tracks the current best and where backups live
|
|
178
|
+
- Phase + phase_note tell Claude exactly where things stand
|
|
179
|
+
|
|
180
|
+
### 2b. System Prompt (prompt.md)
|
|
181
|
+
|
|
182
|
+
Claude's identity, tools, rules, and philosophy. This is the most important file in the
|
|
183
|
+
framework — it determines how Claude behaves. Sections:
|
|
184
|
+
|
|
185
|
+
1. **Identity** — "You are the owner, not a helper. You decide and execute."
|
|
186
|
+
2. **Philosophy** — How to think about failure, when to iterate vs pivot
|
|
187
|
+
3. **Communication model** — How human communicates in (file edits), how agent communicates out (email)
|
|
188
|
+
4. **Available tools** — Exact commands Claude can run, with examples
|
|
189
|
+
5. **Rules/guardrails** — Hard limits that must never be violated
|
|
190
|
+
6. **What to do now** — Decision tree for each invocation
|
|
191
|
+
|
|
192
|
+
### 2c. Roadmap (roadmap.md)
|
|
193
|
+
|
|
194
|
+
Multi-stage plan with graduation criteria per stage. Gives Claude long-term direction
|
|
195
|
+
without micromanaging individual decisions.
|
|
196
|
+
|
|
197
|
+
```markdown
|
|
198
|
+
## Stage 1: Foundation ✅ COMPLETE
|
|
199
|
+
**Graduation criteria (ALL must be met):**
|
|
200
|
+
- [x] Metric A >= threshold
|
|
201
|
+
- [x] Metric B >= threshold
|
|
202
|
+
|
|
203
|
+
## Stage 2: Optimization ← CURRENT
|
|
204
|
+
**Key activities:** (suggestions, not prescriptions)
|
|
205
|
+
**Graduation criteria:**
|
|
206
|
+
- [ ] Metric A >= higher_threshold
|
|
207
|
+
- [ ] At least N experiments completed
|
|
208
|
+
|
|
209
|
+
## Stage 3: Scale
|
|
210
|
+
(future stages give Claude something to work toward)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Why this matters:** Without a roadmap, Claude declares "goal reached" after hitting the
|
|
214
|
+
first milestone. The roadmap gives it permanent forward momentum — there's always a next
|
|
215
|
+
stage.
|
|
216
|
+
|
|
217
|
+
### 2d. Project Journal (journal.json)
|
|
218
|
+
|
|
219
|
+
Accumulated knowledge across all cycles. Every experiment, finding, and lesson. Claude
|
|
220
|
+
reads this every invocation to avoid repeating mistakes.
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"entries": [
|
|
225
|
+
{
|
|
226
|
+
"date": "2026-06-25",
|
|
227
|
+
"event": "Cycle 2 completed — new best score",
|
|
228
|
+
"details": "lr=3e-5 with 3000 steps. Score improved 78.2 → 85.3.",
|
|
229
|
+
"lesson": "Lower LR works better than higher for this task."
|
|
230
|
+
}
|
|
231
|
+
],
|
|
232
|
+
"key_findings": [
|
|
233
|
+
"lr > 1e-4 causes catastrophic regression",
|
|
234
|
+
"Data source A is saturated after 2 cycles"
|
|
235
|
+
]
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 2e. CLAUDE.md
|
|
240
|
+
|
|
241
|
+
Standard Claude Code project context file. Quick reference for paths, commands, and
|
|
242
|
+
constraints. Claude reads this automatically at the start of every invocation.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Component 3: The Philosophy Prompt
|
|
247
|
+
|
|
248
|
+
The most underrated component. Without the right framing, Claude will:
|
|
249
|
+
- Declare "all options exhausted" after 2-3 failures
|
|
250
|
+
- Park itself waiting for human approval
|
|
251
|
+
- Treat each regression as a dead end instead of a data point
|
|
252
|
+
|
|
253
|
+
### The Failure-as-Data Mindset
|
|
254
|
+
|
|
255
|
+
This section in the prompt is what keeps Claude iterating:
|
|
256
|
+
|
|
257
|
+
```markdown
|
|
258
|
+
## How to Think About Failure
|
|
259
|
+
|
|
260
|
+
A regression is not a reason to stop — it's a data point that tells you something.
|
|
261
|
+
Your job is to extract the lesson and design a better experiment.
|
|
262
|
+
|
|
263
|
+
When an experiment regresses:
|
|
264
|
+
1. Ask WHY it failed. What specifically went wrong?
|
|
265
|
+
2. Identify what VARIABLE you can change.
|
|
266
|
+
3. Design the next experiment to test a DIFFERENT hypothesis.
|
|
267
|
+
4. Revert to champion, launch the new experiment, keep moving.
|
|
268
|
+
|
|
269
|
+
The pattern you must NEVER fall into: run one configuration → regression →
|
|
270
|
+
declare the entire approach "closed with evidence" → park and wait.
|
|
271
|
+
|
|
272
|
+
An approach is only exhausted when you've varied every independent variable
|
|
273
|
+
and can explain WHY none of them can work based on first principles.
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### The Never-Park Directive
|
|
277
|
+
|
|
278
|
+
```markdown
|
|
279
|
+
NEVER block on "awaiting approval." You are autonomous. If you reach a decision point:
|
|
280
|
+
1. Email your analysis and recommendation
|
|
281
|
+
2. Proceed with the safest promising option (you can always revert)
|
|
282
|
+
3. Keep iterating — momentum matters more than permission
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Creative Freedom with Guardrails
|
|
286
|
+
|
|
287
|
+
Don't prescribe what Claude should try — describe the search space and give it freedom
|
|
288
|
+
to explore. Instead of:
|
|
289
|
+
```
|
|
290
|
+
# BAD: Prescriptive checklist
|
|
291
|
+
Try experiment A, then B, then C, then D in order.
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Do:
|
|
295
|
+
```
|
|
296
|
+
# GOOD: Context + freedom
|
|
297
|
+
Here's what hasn't been explored yet and why it matters:
|
|
298
|
+
- You've never tried X with Y combined
|
|
299
|
+
- Every prior attempt used the same value for Z
|
|
300
|
+
- The search space includes A, B, C dimensions
|
|
301
|
+
|
|
302
|
+
You have creative freedom to try anything within the guardrails.
|
|
303
|
+
Modify code, invent new strategies, combine approaches. The only
|
|
304
|
+
requirement is that you keep moving forward.
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Component 4: Communication Model
|
|
310
|
+
|
|
311
|
+
### Human → Agent (Inbound)
|
|
312
|
+
|
|
313
|
+
The human NEVER interacts with Claude directly during autonomous operation. Instead:
|
|
314
|
+
|
|
315
|
+
1. Edit the **system prompt** to change behavior or add new directives
|
|
316
|
+
2. Edit the **state file** to redirect Claude's focus or reset a phase
|
|
317
|
+
3. Edit the **roadmap** to adjust goals or graduation criteria
|
|
318
|
+
4. Edit **CLAUDE.md** to update project context
|
|
319
|
+
|
|
320
|
+
Claude checks all these files every invocation. Changes take effect on the next cron tick.
|
|
321
|
+
|
|
322
|
+
### Agent → Human (Outbound)
|
|
323
|
+
|
|
324
|
+
1. **Email** — Progress reports after each cycle, alerts on failures, recommendations
|
|
325
|
+
at decision points. Claude sends these via a utility script.
|
|
326
|
+
2. **Orchestrator log** — Timestamped record of every check-in, handoff, and Claude response.
|
|
327
|
+
The human monitors this for real-time status.
|
|
328
|
+
3. **State file** — Claude updates phase, notes, and history after every action.
|
|
329
|
+
4. **Journal** — Detailed write-up of what was tried, what was learned, what's next.
|
|
330
|
+
|
|
331
|
+
### The "Monitor" Pattern (for the human)
|
|
332
|
+
|
|
333
|
+
The human's workflow:
|
|
334
|
+
```bash
|
|
335
|
+
# Quick status check
|
|
336
|
+
tail -20 output/orchestrator.log
|
|
337
|
+
|
|
338
|
+
# What's Claude working on?
|
|
339
|
+
cat output/state.json | jq '.phase, .phase_note'
|
|
340
|
+
|
|
341
|
+
# Full history
|
|
342
|
+
cat output/state.json | jq '.history'
|
|
343
|
+
|
|
344
|
+
# Redirect Claude (edit a file, next cron tick picks it up)
|
|
345
|
+
vim output/prompt.md
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Component 5: Cron Configuration
|
|
351
|
+
|
|
352
|
+
### Cadence Selection
|
|
353
|
+
|
|
354
|
+
- **Too fast (< 30 min):** Multiple unnecessary check-ins per job. False stale-process
|
|
355
|
+
alarms. Wastes API calls. Claude gets confused by overlapping invocations.
|
|
356
|
+
- **Too slow (> 2 hr):** Long idle gaps between cycle completion and next action.
|
|
357
|
+
Momentum loss.
|
|
358
|
+
- **Sweet spot: 60 minutes.** Long enough for most jobs to complete between ticks.
|
|
359
|
+
Short enough to keep momentum. One hour is the natural unit.
|
|
360
|
+
|
|
361
|
+
```crontab
|
|
362
|
+
0 * * * * cd /path/to/project && python3 orchestrator.py >> output/orchestrator.log 2>&1
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Anti-Patterns
|
|
366
|
+
|
|
367
|
+
- **Don't run the orchestrator AND Claude simultaneously.** The cron job should be the ONLY
|
|
368
|
+
entry point. If you manually trigger Claude while cron is running, they'll fight over
|
|
369
|
+
the state file.
|
|
370
|
+
- **Don't let cron stack.** If a handoff takes 10 minutes and cron fires again, you get
|
|
371
|
+
two Claudes. Use a lockfile:
|
|
372
|
+
```python
|
|
373
|
+
LOCKFILE = Path("/tmp/orchestrator.lock")
|
|
374
|
+
if LOCKFILE.exists():
|
|
375
|
+
pid = int(LOCKFILE.read_text())
|
|
376
|
+
if psutil.pid_exists(pid):
|
|
377
|
+
log("Previous run still active, skipping")
|
|
378
|
+
return
|
|
379
|
+
LOCKFILE.write_text(str(os.getpid()))
|
|
380
|
+
try:
|
|
381
|
+
main()
|
|
382
|
+
finally:
|
|
383
|
+
LOCKFILE.unlink(missing_ok=True)
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Deployment Checklist (General)
|
|
389
|
+
|
|
390
|
+
### 1. Define the Task
|
|
391
|
+
|
|
392
|
+
- What is the agent trying to achieve? (measurable goal)
|
|
393
|
+
- What are the stages/milestones? (roadmap)
|
|
394
|
+
- What tools does the agent need? (commands, scripts, APIs)
|
|
395
|
+
- What are the hard limits? (cost caps, rate limits, destructive actions to prohibit)
|
|
396
|
+
- How do you measure success? (metrics, benchmarks, KPIs)
|
|
397
|
+
|
|
398
|
+
### 2. Build the State Layer
|
|
399
|
+
|
|
400
|
+
```
|
|
401
|
+
project/
|
|
402
|
+
output/
|
|
403
|
+
state.json # Current status, phase, history
|
|
404
|
+
journal.json # Accumulated knowledge
|
|
405
|
+
orchestrator.log # Timestamped activity log
|
|
406
|
+
prompt.md # System prompt (identity + tools + rules + philosophy)
|
|
407
|
+
roadmap.md # Staged plan with graduation criteria
|
|
408
|
+
CLAUDE.md # Project context for Claude Code
|
|
409
|
+
orchestrator.py # Cron-triggered orchestrator
|
|
410
|
+
utils/
|
|
411
|
+
send_report.py # Email utility (or Slack, webhook, etc.)
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### 3. Write the System Prompt
|
|
415
|
+
|
|
416
|
+
Must include:
|
|
417
|
+
- [ ] Identity ("you are the owner, not a helper")
|
|
418
|
+
- [ ] Failure philosophy ("regression = data point, not dead end")
|
|
419
|
+
- [ ] Communication model ("human edits files, you send email")
|
|
420
|
+
- [ ] Available tools (exact commands with examples)
|
|
421
|
+
- [ ] Guardrails (hard limits, cost caps, things that must never happen)
|
|
422
|
+
- [ ] Decision tree ("what to do now" section)
|
|
423
|
+
- [ ] Never-park directive ("never set phase to awaiting/idle/blocked")
|
|
424
|
+
|
|
425
|
+
### 4. Write the Orchestrator
|
|
426
|
+
|
|
427
|
+
Must handle:
|
|
428
|
+
- [ ] State loading with defensive accessors
|
|
429
|
+
- [ ] Process detection (is anything running?)
|
|
430
|
+
- [ ] Progress reporting (parse logs for status)
|
|
431
|
+
- [ ] Stale process detection (log age check)
|
|
432
|
+
- [ ] Transition detection (completed / failed / idle)
|
|
433
|
+
- [ ] Claude handoff (full context prompt → CLI → log response)
|
|
434
|
+
- [ ] Timeout handling (Claude CLI can hang)
|
|
435
|
+
- [ ] Unknown phase handling (don't crash on unexpected state)
|
|
436
|
+
- [ ] Lockfile to prevent cron stacking
|
|
437
|
+
|
|
438
|
+
### 5. Set Up Cron
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
# Install
|
|
442
|
+
crontab -e
|
|
443
|
+
# Add
|
|
444
|
+
0 * * * * cd /path/to/project && python3 orchestrator.py >> output/orchestrator.log 2>&1
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### 6. Test the Loop
|
|
448
|
+
|
|
449
|
+
1. Set state to a known phase
|
|
450
|
+
2. Run orchestrator manually: `python3 orchestrator.py`
|
|
451
|
+
3. Verify Claude received context and took action
|
|
452
|
+
4. Check state file was updated
|
|
453
|
+
5. Check journal was updated
|
|
454
|
+
6. Check email/notification was sent
|
|
455
|
+
7. Run orchestrator again — verify it detects the new state correctly
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
## Example: Marketing Campaign Agent
|
|
460
|
+
|
|
461
|
+
Applying this framework to a marketing use case:
|
|
462
|
+
|
|
463
|
+
**Task:** Autonomous A/B testing and optimization of ad campaigns.
|
|
464
|
+
|
|
465
|
+
**Roadmap stages:**
|
|
466
|
+
1. Baseline — run initial campaigns, establish control metrics
|
|
467
|
+
2. Hypothesis generation — analyze performance data, identify underperforming segments
|
|
468
|
+
3. Test design — create variants, set up A/B splits
|
|
469
|
+
4. Iteration — run tests, analyze results, promote winners, design next test
|
|
470
|
+
5. Scale — expand winning strategies across channels
|
|
471
|
+
|
|
472
|
+
**Tools:**
|
|
473
|
+
```
|
|
474
|
+
# Ad platform CLI / API calls
|
|
475
|
+
python3 tools/create_variant.py --campaign X --variant "copy text" --audience Y
|
|
476
|
+
python3 tools/get_metrics.py --campaign X --since 24h
|
|
477
|
+
python3 tools/promote_winner.py --campaign X --variant Z
|
|
478
|
+
python3 tools/pause_underperformer.py --campaign X --threshold 0.5
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
**Guardrails:**
|
|
482
|
+
- Daily spend cap: never exceed $X per campaign
|
|
483
|
+
- Never pause ALL variants simultaneously
|
|
484
|
+
- Always keep the control running
|
|
485
|
+
- Never modify campaigns flagged as "locked" in state
|
|
486
|
+
- Minimum test duration: 48 hours before drawing conclusions
|
|
487
|
+
|
|
488
|
+
**State:**
|
|
489
|
+
```json
|
|
490
|
+
{
|
|
491
|
+
"phase": "testing-round-3",
|
|
492
|
+
"active_tests": [
|
|
493
|
+
{"campaign": "summer-2026", "variant": "urgency-copy", "started": "2026-06-25", "ctr": 3.2}
|
|
494
|
+
],
|
|
495
|
+
"champion": {"variant": "social-proof-v2", "ctr": 4.1, "cpa": 12.50},
|
|
496
|
+
"history": [...]
|
|
497
|
+
}
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
**Philosophy prompt addition:**
|
|
501
|
+
```
|
|
502
|
+
A test that underperforms the control is not a failure — it eliminates a hypothesis.
|
|
503
|
+
Your job is to generate better hypotheses. Analyze WHY the variant underperformed
|
|
504
|
+
(wrong audience? wrong channel? wrong time of day? copy too long?) and design the
|
|
505
|
+
next test to isolate that variable.
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## Groove Integration Plan
|
|
511
|
+
|
|
512
|
+
To make this deployable from Groove as a first-class feature:
|
|
513
|
+
|
|
514
|
+
### Core Abstraction
|
|
515
|
+
|
|
516
|
+
```yaml
|
|
517
|
+
# groove_agent.yaml — agent definition
|
|
518
|
+
name: "campaign-optimizer"
|
|
519
|
+
description: "Autonomous A/B testing for ad campaigns"
|
|
520
|
+
cadence: "0 * * * *" # hourly
|
|
521
|
+
timeout: 600 # max 10 min per handoff
|
|
522
|
+
|
|
523
|
+
state:
|
|
524
|
+
file: output/state.json
|
|
525
|
+
schema: schemas/campaign_state.json # optional validation
|
|
526
|
+
|
|
527
|
+
prompt:
|
|
528
|
+
file: prompt.md
|
|
529
|
+
|
|
530
|
+
roadmap:
|
|
531
|
+
file: roadmap.md
|
|
532
|
+
|
|
533
|
+
tools:
|
|
534
|
+
- name: "get_metrics"
|
|
535
|
+
command: "python3 tools/get_metrics.py"
|
|
536
|
+
- name: "create_variant"
|
|
537
|
+
command: "python3 tools/create_variant.py"
|
|
538
|
+
guardrail: "spend_cap_check"
|
|
539
|
+
|
|
540
|
+
guardrails:
|
|
541
|
+
spend_cap:
|
|
542
|
+
type: "pre_execution_check"
|
|
543
|
+
command: "python3 tools/check_spend.py --max 500"
|
|
544
|
+
|
|
545
|
+
notifications:
|
|
546
|
+
- type: email
|
|
547
|
+
to: ryan@axomlabs.ai
|
|
548
|
+
- type: slack
|
|
549
|
+
channel: "#agent-alerts"
|
|
550
|
+
|
|
551
|
+
logs:
|
|
552
|
+
orchestrator: output/orchestrator.log
|
|
553
|
+
agent: output/agent_diagnosis.log
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### Groove CLI
|
|
557
|
+
|
|
558
|
+
```bash
|
|
559
|
+
# Deploy a new agent
|
|
560
|
+
groove agent create --config groove_agent.yaml
|
|
561
|
+
|
|
562
|
+
# Check status
|
|
563
|
+
groove agent status campaign-optimizer
|
|
564
|
+
|
|
565
|
+
# View recent activity
|
|
566
|
+
groove agent logs campaign-optimizer --tail 50
|
|
567
|
+
|
|
568
|
+
# Redirect the agent (edit prompt, next tick picks it up)
|
|
569
|
+
groove agent edit-prompt campaign-optimizer
|
|
570
|
+
|
|
571
|
+
# Pause/resume
|
|
572
|
+
groove agent pause campaign-optimizer
|
|
573
|
+
groove agent resume campaign-optimizer
|
|
574
|
+
|
|
575
|
+
# One-shot manual trigger (outside cron)
|
|
576
|
+
groove agent trigger campaign-optimizer
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
### Groove Dashboard
|
|
580
|
+
|
|
581
|
+
- **Agent list** — all deployed agents, current phase, last activity, health
|
|
582
|
+
- **Activity feed** — real-time log of what each agent is doing
|
|
583
|
+
- **Metrics** — per-agent: cycles completed, success rate, time between actions
|
|
584
|
+
- **Controls** — pause, resume, trigger, edit prompt, view state
|
|
585
|
+
- **Alerts** — agent stuck, cost threshold hit, consecutive failures
|
|
586
|
+
|
|
587
|
+
### Template Library
|
|
588
|
+
|
|
589
|
+
Pre-built agent templates for common use cases:
|
|
590
|
+
|
|
591
|
+
| Template | Use Case | Cadence |
|
|
592
|
+
|----------|----------|---------|
|
|
593
|
+
| `ml-trainer` | Autonomous model training/eval loop | 60 min |
|
|
594
|
+
| `campaign-optimizer` | Ad A/B testing and optimization | 60 min |
|
|
595
|
+
| `content-pipeline` | Content generation, review, publish | 30 min |
|
|
596
|
+
| `data-monitor` | Data quality monitoring and alerting | 15 min |
|
|
597
|
+
| `code-reviewer` | Continuous PR review and feedback | 30 min |
|
|
598
|
+
| `seo-optimizer` | Keyword research, content optimization | 120 min |
|
|
599
|
+
| `report-generator` | Periodic business intelligence reports | daily |
|
|
600
|
+
| `competitor-tracker` | Monitor competitor pricing/features | 120 min |
|
|
601
|
+
|
|
602
|
+
Each template ships with: orchestrator.py, prompt.md, roadmap.md, state schema,
|
|
603
|
+
example tools, and guardrails appropriate to the domain.
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## Lessons Learned (from GRAFT deployment)
|
|
608
|
+
|
|
609
|
+
### What Worked
|
|
610
|
+
1. **File-based communication.** Editing a prompt file is the most natural way to redirect
|
|
611
|
+
an agent. No API calls, no webhooks, no auth — just edit a file and wait for the next tick.
|
|
612
|
+
|
|
613
|
+
2. **Journal as memory.** Claude has no memory between invocations. The journal IS its
|
|
614
|
+
memory. Every lesson, every failure, every finding persists across cycles.
|
|
615
|
+
|
|
616
|
+
3. **Champion/backup pattern.** Always preserve the best result before experimenting.
|
|
617
|
+
This makes Claude fearless — any experiment can be safely reverted.
|
|
618
|
+
|
|
619
|
+
4. **Dumb orchestrator, smart agent.** Keeping decision logic in the prompt (not code)
|
|
620
|
+
means you can change behavior without deploying. Edit a markdown file and the agent
|
|
621
|
+
adapts on the next tick.
|
|
622
|
+
|
|
623
|
+
5. **Email for outbound communication.** Simple, async, doesn't require the human to be
|
|
624
|
+
watching a dashboard. Claude emails when something important happens.
|
|
625
|
+
|
|
626
|
+
### What Failed (and fixes)
|
|
627
|
+
|
|
628
|
+
1. **Claude parks itself.** Without explicit never-park directives AND a failure philosophy,
|
|
629
|
+
Claude will declare "all options exhausted" after 2-3 regressions. Fix: the "How to Think
|
|
630
|
+
About Failure" section in the prompt. Frame the search space, not the checklist.
|
|
631
|
+
|
|
632
|
+
2. **Prescriptive experiment lists.** Telling Claude exactly what to try (experiment A, B, C)
|
|
633
|
+
defeats the purpose. It follows the list mechanically instead of thinking creatively.
|
|
634
|
+
Fix: describe the unexplored dimensions and give creative freedom.
|
|
635
|
+
|
|
636
|
+
3. **Stale log false alarms.** The orchestrator checked the training log during eval phases,
|
|
637
|
+
triggering stale process warnings that killed healthy eval runs. Fix: use the correct
|
|
638
|
+
log for the current phase.
|
|
639
|
+
|
|
640
|
+
4. **Claude writes garbage to state.** It will write strings where you expect dicts, null
|
|
641
|
+
where you expect objects, 500-word essays in phase names. Fix: defensive accessors
|
|
642
|
+
everywhere. Never trust the shape of state values.
|
|
643
|
+
|
|
644
|
+
5. **Cron too fast (30 min).** Caused 4-10 unnecessary check-ins per job, false alarms
|
|
645
|
+
during long-running tasks, and confusion from overlapping handoffs. Fix: 60 min cadence
|
|
646
|
+
for most tasks.
|
|
647
|
+
|
|
648
|
+
6. **Claude blocks on approval.** Despite saying "you're autonomous," Claude would email
|
|
649
|
+
recommendations and set phase to "awaiting_decision." Fix: explicit directive + make
|
|
650
|
+
clear that human communicates via file edits, not email replies.
|
|
651
|
+
|
|
652
|
+
7. **Zombie processes.** Long-running evaluation processes that hang or get orphaned. After
|
|
653
|
+
a week, had 42 zombie processes consuming 21GB RAM. Fix: stale process detection +
|
|
654
|
+
periodic cleanup.
|
|
Binary file
|
|
@@ -28,6 +28,7 @@ import { registerFileRoutes, resetEditorRoot } from './routes/files.js';
|
|
|
28
28
|
import { registerNetworkRoutes } from './routes/network.js';
|
|
29
29
|
import { registerScheduleRoutes } from './routes/schedules.js';
|
|
30
30
|
import { registerInnerChatRoutes } from './routes/innerchat.js';
|
|
31
|
+
import { registerAutoAgentRoutes } from './routes/auto-agents.js';
|
|
31
32
|
|
|
32
33
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
33
34
|
const pkgVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
@@ -127,7 +128,7 @@ export function createApi(app, daemon) {
|
|
|
127
128
|
next();
|
|
128
129
|
});
|
|
129
130
|
|
|
130
|
-
app.use(express.json({ limit: '
|
|
131
|
+
app.use(express.json({ limit: '100mb' }));
|
|
131
132
|
|
|
132
133
|
// Health check
|
|
133
134
|
app.get('/api/health', (req, res) => {
|
|
@@ -177,6 +178,7 @@ export function createApi(app, daemon) {
|
|
|
177
178
|
registerNetworkRoutes(app, daemon);
|
|
178
179
|
registerScheduleRoutes(app, daemon);
|
|
179
180
|
registerInnerChatRoutes(app, daemon);
|
|
181
|
+
registerAutoAgentRoutes(app, daemon);
|
|
180
182
|
|
|
181
183
|
|
|
182
184
|
// Token usage
|