openrune 1.0.2 → 1.1.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/README.ko.md +37 -0
- package/README.md +37 -0
- package/bin/rune.js +236 -0
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -71,6 +71,7 @@ Rune은 다른 접근을 합니다: **에이전트가 파일입니다.**
|
|
|
71
71
|
| **스케줄링** | 수동 실행만 가능 | Cron, 파일 변경, git-commit 트리거 |
|
|
72
72
|
| **권한** | 세션에서 상속 | 에이전트별 제어 (`fileWrite`, `bash`, `allowPaths`) |
|
|
73
73
|
| **실행** | 대화형 | 헤드리스, 파이프라인, CI/CD 지원 |
|
|
74
|
+
| **자기 수정** | 기본 제공 없음 | `rune loop` — 자동 리뷰-수정 반복 |
|
|
74
75
|
|
|
75
76
|
Rune 에이전트는 세션, 머신, 팀을 넘어 살아남습니다. 한 번 만들면 영원히 실행.
|
|
76
77
|
|
|
@@ -214,6 +215,41 @@ rune pipe architect.rune coder.rune "Build a REST API with Express" --auto
|
|
|
214
215
|
|
|
215
216
|
architect가 설계 → coder가 구현 (파일 작성, 의존성 설치).
|
|
216
217
|
|
|
218
|
+
### 자기 수정 루프
|
|
219
|
+
|
|
220
|
+
에이전트가 자동으로 자신의 작업을 리뷰하고 수정합니다:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
rune loop coder.rune reviewer.rune "Build a REST API with Express" --until "no critical issues" --max-iterations 3 --auto
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
🔁 Starting self-correction loop (max 3 iterations)
|
|
228
|
+
Stop condition: "no critical issues"
|
|
229
|
+
|
|
230
|
+
━━━ Iteration 1/3 ━━━
|
|
231
|
+
|
|
232
|
+
▶ [doer] coder — API 구현
|
|
233
|
+
✓ coder done
|
|
234
|
+
|
|
235
|
+
▶ [reviewer] reviewer — 치명적 이슈 2개 발견
|
|
236
|
+
✓ reviewer done
|
|
237
|
+
|
|
238
|
+
━━━ Iteration 2/3 ━━━
|
|
239
|
+
|
|
240
|
+
▶ [doer] coder — 이슈 수정
|
|
241
|
+
✓ coder done
|
|
242
|
+
|
|
243
|
+
▶ [reviewer] reviewer — "no critical issues found"
|
|
244
|
+
✓ reviewer done
|
|
245
|
+
|
|
246
|
+
✅ Condition met: "no critical issues"
|
|
247
|
+
|
|
248
|
+
🔁 Loop completed after 2 iterations
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
구현자가 구현하고, 리뷰어가 리뷰합니다. 문제가 발견되면 피드백이 자동으로 구현자에게 전달됩니다 — 조건이 충족되거나 최대 반복 횟수에 도달할 때까지.
|
|
252
|
+
|
|
217
253
|
### 자동화 트리거
|
|
218
254
|
|
|
219
255
|
```bash
|
|
@@ -324,6 +360,7 @@ rune open reviewer.rune
|
|
|
324
360
|
| `rune new <name> [--role "..."]` | 에이전트 생성 |
|
|
325
361
|
| `rune run <file> "prompt" [--auto] [--output json]` | 헤드리스 실행 |
|
|
326
362
|
| `rune pipe <a> <b> [...] "prompt" [--auto]` | 에이전트 체이닝 |
|
|
363
|
+
| `rune loop <doer> <reviewer> "prompt" [--until "..."] [--max-iterations N] [--auto]` | 자기 수정 루프 |
|
|
327
364
|
| `rune watch <file> --on <event> --prompt "..."` | 자동화 트리거 |
|
|
328
365
|
| `rune open <file>` | 데스크톱 UI |
|
|
329
366
|
| `rune list` | 현재 디렉토리의 에이전트 목록 |
|
package/README.md
CHANGED
|
@@ -71,6 +71,7 @@ Rune takes a different approach: **agents are files.**
|
|
|
71
71
|
| **Scheduling** | Manual execution only | Cron, file-change, and git-commit triggers |
|
|
72
72
|
| **Permissions** | Inherited from session | Per-agent controls (`fileWrite`, `bash`, `allowPaths`) |
|
|
73
73
|
| **Execution** | Interactive | Headless, pipelines, CI/CD-ready |
|
|
74
|
+
| **Self-correction** | Not built-in | `rune loop` — automatic review-fix cycles |
|
|
74
75
|
|
|
75
76
|
Rune agents survive across sessions, machines, and teams. Build once, run forever.
|
|
76
77
|
|
|
@@ -214,6 +215,41 @@ rune pipe architect.rune coder.rune "Build a REST API with Express" --auto
|
|
|
214
215
|
|
|
215
216
|
architect designs → coder implements (writes files, installs deps).
|
|
216
217
|
|
|
218
|
+
### Self-correction loop
|
|
219
|
+
|
|
220
|
+
Agents review and fix their own work automatically:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
rune loop coder.rune reviewer.rune "Build a REST API with Express" --until "no critical issues" --max-iterations 3 --auto
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
🔁 Starting self-correction loop (max 3 iterations)
|
|
228
|
+
Stop condition: "no critical issues"
|
|
229
|
+
|
|
230
|
+
━━━ Iteration 1/3 ━━━
|
|
231
|
+
|
|
232
|
+
▶ [doer] coder — implements the API
|
|
233
|
+
✓ coder done
|
|
234
|
+
|
|
235
|
+
▶ [reviewer] reviewer — finds 2 critical issues
|
|
236
|
+
✓ reviewer done
|
|
237
|
+
|
|
238
|
+
━━━ Iteration 2/3 ━━━
|
|
239
|
+
|
|
240
|
+
▶ [doer] coder — fixes the issues
|
|
241
|
+
✓ coder done
|
|
242
|
+
|
|
243
|
+
▶ [reviewer] reviewer — "no critical issues found"
|
|
244
|
+
✓ reviewer done
|
|
245
|
+
|
|
246
|
+
✅ Condition met: "no critical issues"
|
|
247
|
+
|
|
248
|
+
🔁 Loop completed after 2 iterations
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The doer implements, the reviewer reviews. If issues are found, feedback goes back to the doer automatically — until the condition is met or max iterations are reached.
|
|
252
|
+
|
|
217
253
|
### Automated triggers
|
|
218
254
|
|
|
219
255
|
```bash
|
|
@@ -324,6 +360,7 @@ Or double-click any `.rune` file in Finder.
|
|
|
324
360
|
| `rune new <name> [--role "..."]` | Create agent |
|
|
325
361
|
| `rune run <file> "prompt" [--auto] [--output json]` | Run headlessly |
|
|
326
362
|
| `rune pipe <a> <b> [...] "prompt" [--auto]` | Chain agents |
|
|
363
|
+
| `rune loop <doer> <reviewer> "prompt" [--until "..."] [--max-iterations N] [--auto]` | Self-correction loop |
|
|
327
364
|
| `rune watch <file> --on <event> --prompt "..."` | Automated triggers |
|
|
328
365
|
| `rune open <file>` | Desktop UI |
|
|
329
366
|
| `rune list` | List agents in current directory |
|
package/bin/rune.js
CHANGED
|
@@ -27,6 +27,7 @@ switch (command) {
|
|
|
27
27
|
case 'open': return openRune(args[0])
|
|
28
28
|
case 'run': return runRune(args[0], args.slice(1))
|
|
29
29
|
case 'pipe': return pipeRunes(args)
|
|
30
|
+
case 'loop': return loopRunes(args)
|
|
30
31
|
case 'watch': return watchRune(args[0], args.slice(1))
|
|
31
32
|
case 'list': return listRunes()
|
|
32
33
|
case 'uninstall': return uninstall()
|
|
@@ -1156,6 +1157,236 @@ async function pipeRunes(args) {
|
|
|
1156
1157
|
}
|
|
1157
1158
|
}
|
|
1158
1159
|
|
|
1160
|
+
// ── loop (self-correction) ──────────────────────
|
|
1161
|
+
|
|
1162
|
+
async function loopRunes(args) {
|
|
1163
|
+
// Parse: rune loop coder.rune reviewer.rune "prompt" [--until "condition"] [--max-iterations N] [--auto]
|
|
1164
|
+
const runeFiles = []
|
|
1165
|
+
let prompt = ''
|
|
1166
|
+
let untilCondition = ''
|
|
1167
|
+
let maxIterations = 5
|
|
1168
|
+
let autoMode = false
|
|
1169
|
+
|
|
1170
|
+
for (let i = 0; i < args.length; i++) {
|
|
1171
|
+
if (args[i] === '--until' && args[i + 1]) {
|
|
1172
|
+
untilCondition = args[++i]
|
|
1173
|
+
} else if (args[i] === '--max-iterations' && args[i + 1]) {
|
|
1174
|
+
maxIterations = parseInt(args[++i], 10)
|
|
1175
|
+
} else if (args[i] === '--auto') {
|
|
1176
|
+
autoMode = true
|
|
1177
|
+
} else if (args[i].endsWith('.rune')) {
|
|
1178
|
+
runeFiles.push(args[i])
|
|
1179
|
+
} else if (!prompt) {
|
|
1180
|
+
prompt = args[i]
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
if (runeFiles.length < 2 || !prompt) {
|
|
1185
|
+
console.log('Usage: rune loop <doer.rune> <reviewer.rune> "prompt" [--until "condition"] [--max-iterations N] [--auto]')
|
|
1186
|
+
console.log('')
|
|
1187
|
+
console.log('Options:')
|
|
1188
|
+
console.log(' --until "..." Stop when the reviewer\'s output contains this text')
|
|
1189
|
+
console.log(' --max-iterations N Maximum number of loop iterations (default: 5)')
|
|
1190
|
+
console.log(' --auto Allow agents to write files and run commands')
|
|
1191
|
+
console.log('')
|
|
1192
|
+
console.log('Example:')
|
|
1193
|
+
console.log(' rune loop coder.rune reviewer.rune "Build a REST API" --until "no critical issues" --max-iterations 3 --auto')
|
|
1194
|
+
console.log('')
|
|
1195
|
+
console.log('The first agent implements, the last agent reviews.')
|
|
1196
|
+
console.log('If the reviewer finds issues, feedback is sent back to the first agent automatically.')
|
|
1197
|
+
process.exit(1)
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
// Validate files
|
|
1201
|
+
for (const file of runeFiles) {
|
|
1202
|
+
const filePath = path.resolve(process.cwd(), file)
|
|
1203
|
+
if (!fs.existsSync(filePath)) {
|
|
1204
|
+
console.error(` ❌ File not found: ${filePath}`)
|
|
1205
|
+
process.exit(1)
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
const doerFile = runeFiles[0]
|
|
1210
|
+
const reviewerFile = runeFiles[runeFiles.length - 1]
|
|
1211
|
+
const doerPath = path.resolve(process.cwd(), doerFile)
|
|
1212
|
+
const reviewerPath = path.resolve(process.cwd(), reviewerFile)
|
|
1213
|
+
|
|
1214
|
+
let currentPrompt = prompt
|
|
1215
|
+
let iteration = 0
|
|
1216
|
+
let converged = false
|
|
1217
|
+
|
|
1218
|
+
console.log(`\n🔁 Starting self-correction loop (max ${maxIterations} iterations)`)
|
|
1219
|
+
if (untilCondition) console.log(` Stop condition: "${untilCondition}"`)
|
|
1220
|
+
console.log('')
|
|
1221
|
+
|
|
1222
|
+
while (iteration < maxIterations && !converged) {
|
|
1223
|
+
iteration++
|
|
1224
|
+
console.log(` ━━━ Iteration ${iteration}/${maxIterations} ━━━\n`)
|
|
1225
|
+
|
|
1226
|
+
// Step 1: Doer implements
|
|
1227
|
+
const doerRune = JSON.parse(fs.readFileSync(doerPath, 'utf-8'))
|
|
1228
|
+
const doerFolder = path.dirname(doerPath)
|
|
1229
|
+
const doerSystem = []
|
|
1230
|
+
if (doerRune.role) doerSystem.push(`Your role: ${doerRune.role}`)
|
|
1231
|
+
if (doerRune.memory && doerRune.memory.length > 0) {
|
|
1232
|
+
doerSystem.push('Saved memory:')
|
|
1233
|
+
doerRune.memory.forEach((m, j) => doerSystem.push(`${j + 1}. ${m}`))
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
const doerContext = iteration > 1
|
|
1237
|
+
? `You are in iteration ${iteration} of a self-correction loop. The reviewer found issues with your previous work:\n\n${currentPrompt}\n\nFix the issues and improve your implementation.`
|
|
1238
|
+
: currentPrompt
|
|
1239
|
+
|
|
1240
|
+
console.log(` ▶ [doer] ${doerRune.name} (${doerRune.role || 'assistant'})`)
|
|
1241
|
+
|
|
1242
|
+
const doerOutput = await runAgent(doerRune.name, doerFolder, doerSystem, doerContext, autoMode)
|
|
1243
|
+
|
|
1244
|
+
doerRune.history = doerRune.history || []
|
|
1245
|
+
doerRune.history.push({ role: 'user', text: doerContext, ts: Date.now() })
|
|
1246
|
+
doerRune.history.push({ role: 'assistant', text: doerOutput, ts: Date.now() })
|
|
1247
|
+
fs.writeFileSync(doerPath, JSON.stringify(doerRune, null, 2))
|
|
1248
|
+
|
|
1249
|
+
console.log(` ✓ ${doerRune.name} done\n`)
|
|
1250
|
+
|
|
1251
|
+
// Step 2: Reviewer reviews
|
|
1252
|
+
const reviewerRune = JSON.parse(fs.readFileSync(reviewerPath, 'utf-8'))
|
|
1253
|
+
const reviewerFolder = path.dirname(reviewerPath)
|
|
1254
|
+
const reviewerSystem = []
|
|
1255
|
+
if (reviewerRune.role) reviewerSystem.push(`Your role: ${reviewerRune.role}`)
|
|
1256
|
+
if (reviewerRune.memory && reviewerRune.memory.length > 0) {
|
|
1257
|
+
reviewerSystem.push('Saved memory:')
|
|
1258
|
+
reviewerRune.memory.forEach((m, j) => reviewerSystem.push(`${j + 1}. ${m}`))
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
const reviewerContext = `You are the reviewer in iteration ${iteration} of a self-correction loop. Review the work done by ${doerRune.name}:\n\n${doerOutput}\n\nIf there are issues, describe them clearly so the implementer can fix them. If the work is satisfactory, say so clearly.`
|
|
1262
|
+
|
|
1263
|
+
console.log(` ▶ [reviewer] ${reviewerRune.name} (${reviewerRune.role || 'assistant'})`)
|
|
1264
|
+
|
|
1265
|
+
const reviewerOutput = await runAgent(reviewerRune.name, reviewerFolder, reviewerSystem, reviewerContext, false)
|
|
1266
|
+
|
|
1267
|
+
reviewerRune.history = reviewerRune.history || []
|
|
1268
|
+
reviewerRune.history.push({ role: 'user', text: reviewerContext, ts: Date.now() })
|
|
1269
|
+
reviewerRune.history.push({ role: 'assistant', text: reviewerOutput, ts: Date.now() })
|
|
1270
|
+
fs.writeFileSync(reviewerPath, JSON.stringify(reviewerRune, null, 2))
|
|
1271
|
+
|
|
1272
|
+
console.log(` ✓ ${reviewerRune.name} done\n`)
|
|
1273
|
+
|
|
1274
|
+
// Check convergence
|
|
1275
|
+
if (untilCondition) {
|
|
1276
|
+
const lower = reviewerOutput.toLowerCase()
|
|
1277
|
+
if (lower.includes(untilCondition.toLowerCase())) {
|
|
1278
|
+
converged = true
|
|
1279
|
+
console.log(` ✅ Condition met: "${untilCondition}"`)
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
if (!converged) {
|
|
1284
|
+
currentPrompt = reviewerOutput
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
if (!converged && iteration >= maxIterations) {
|
|
1289
|
+
console.log(` ⚠️ Max iterations (${maxIterations}) reached`)
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
console.log(`\n🔁 Loop completed after ${iteration} iteration${iteration > 1 ? 's' : ''}\n`)
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
async function runAgent(name, folderPath, systemParts, prompt, autoMode) {
|
|
1296
|
+
if (autoMode) {
|
|
1297
|
+
const mcpPath = path.join(folderPath, '.mcp.json')
|
|
1298
|
+
const mcpBackup = path.join(folderPath, '.mcp.json.loop.bak')
|
|
1299
|
+
let mcpHidden = false
|
|
1300
|
+
if (fs.existsSync(mcpPath)) {
|
|
1301
|
+
fs.renameSync(mcpPath, mcpBackup)
|
|
1302
|
+
mcpHidden = true
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
const claudeArgs = ['-p', '--print',
|
|
1306
|
+
'--dangerously-skip-permissions',
|
|
1307
|
+
'--verbose',
|
|
1308
|
+
'--output-format', 'stream-json',
|
|
1309
|
+
]
|
|
1310
|
+
if (systemParts.length > 0) {
|
|
1311
|
+
claudeArgs.push('--system-prompt', systemParts.join('\n'))
|
|
1312
|
+
}
|
|
1313
|
+
claudeArgs.push(prompt)
|
|
1314
|
+
|
|
1315
|
+
const output = await new Promise((resolve, reject) => {
|
|
1316
|
+
const child = spawn('claude', claudeArgs, {
|
|
1317
|
+
cwd: folderPath,
|
|
1318
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
1319
|
+
env: { ...process.env },
|
|
1320
|
+
})
|
|
1321
|
+
|
|
1322
|
+
let fullOutput = ''
|
|
1323
|
+
let buffer = ''
|
|
1324
|
+
child.stdout.on('data', (data) => {
|
|
1325
|
+
buffer += data.toString()
|
|
1326
|
+
const lines = buffer.split('\n')
|
|
1327
|
+
buffer = lines.pop()
|
|
1328
|
+
for (const line of lines) {
|
|
1329
|
+
if (!line.trim()) continue
|
|
1330
|
+
try {
|
|
1331
|
+
const event = JSON.parse(line)
|
|
1332
|
+
if (event.type === 'assistant' && event.message && event.message.content) {
|
|
1333
|
+
for (const block of event.message.content) {
|
|
1334
|
+
if (block.type === 'tool_use') {
|
|
1335
|
+
const tool = block.name || 'unknown'
|
|
1336
|
+
const input = block.input || {}
|
|
1337
|
+
if (tool === 'Bash') console.log(` ▶ Bash: ${(input.command || '').slice(0, 120)}`)
|
|
1338
|
+
else if (tool === 'Write') console.log(` ▶ Write: ${input.file_path || ''}`)
|
|
1339
|
+
else if (tool === 'Edit') console.log(` ▶ Edit: ${input.file_path || ''}`)
|
|
1340
|
+
else if (tool === 'Read') console.log(` ▶ Read: ${input.file_path || ''}`)
|
|
1341
|
+
else console.log(` ▶ ${tool}`)
|
|
1342
|
+
} else if (block.type === 'text' && block.text && block.text.trim()) {
|
|
1343
|
+
console.log(` 💬 ${block.text.trim().slice(0, 200)}`)
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
if (event.type === 'result') {
|
|
1348
|
+
fullOutput = event.result || ''
|
|
1349
|
+
}
|
|
1350
|
+
} catch {}
|
|
1351
|
+
}
|
|
1352
|
+
})
|
|
1353
|
+
child.stderr.on('data', (d) => { process.stderr.write(d) })
|
|
1354
|
+
child.on('close', (code) => {
|
|
1355
|
+
if (mcpHidden && fs.existsSync(mcpBackup)) fs.renameSync(mcpBackup, mcpPath)
|
|
1356
|
+
if (code !== 0) reject(new Error(`Agent ${name} exited with code ${code}`))
|
|
1357
|
+
else resolve(fullOutput.trim())
|
|
1358
|
+
})
|
|
1359
|
+
})
|
|
1360
|
+
|
|
1361
|
+
return output
|
|
1362
|
+
} else {
|
|
1363
|
+
const tmpdir = require('os').tmpdir()
|
|
1364
|
+
const claudeArgs = ['-p', '--print', '--add-dir', folderPath]
|
|
1365
|
+
if (systemParts.length > 0) {
|
|
1366
|
+
claudeArgs.push('--system-prompt', systemParts.join('\n') + `\nWorking folder: ${folderPath}`)
|
|
1367
|
+
}
|
|
1368
|
+
claudeArgs.push('--', prompt)
|
|
1369
|
+
|
|
1370
|
+
const output = await new Promise((resolve, reject) => {
|
|
1371
|
+
const child = spawn('claude', claudeArgs, {
|
|
1372
|
+
cwd: tmpdir,
|
|
1373
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
1374
|
+
env: { ...process.env },
|
|
1375
|
+
})
|
|
1376
|
+
|
|
1377
|
+
let stdout = ''
|
|
1378
|
+
child.stdout.on('data', (d) => { stdout += d.toString() })
|
|
1379
|
+
child.stderr.on('data', (d) => { process.stderr.write(d) })
|
|
1380
|
+
child.on('close', (code) => {
|
|
1381
|
+
if (code !== 0) reject(new Error(`Agent ${name} exited with code ${code}`))
|
|
1382
|
+
else resolve(stdout.trim())
|
|
1383
|
+
})
|
|
1384
|
+
})
|
|
1385
|
+
|
|
1386
|
+
return output
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1159
1390
|
// ── watch (triggers) ────────────────────────────
|
|
1160
1391
|
|
|
1161
1392
|
function watchRune(file, restArgs) {
|
|
@@ -1425,6 +1656,10 @@ Usage:
|
|
|
1425
1656
|
--log <file.json> Save structured log (tool calls, cost, duration)
|
|
1426
1657
|
rune pipe <a.rune> <b.rune> ... "prompt" Chain agents in a pipeline
|
|
1427
1658
|
--output json|text Output format (default: text)
|
|
1659
|
+
rune loop <doer.rune> <reviewer.rune> "prompt" Self-correction loop
|
|
1660
|
+
--until "condition" Stop when reviewer output contains this text
|
|
1661
|
+
--max-iterations N Max iterations (default: 5)
|
|
1662
|
+
--auto Allow agents to write files and run commands
|
|
1428
1663
|
rune watch <file.rune> Set up automated triggers
|
|
1429
1664
|
--on <event> Event: file-change, git-commit, git-push, cron
|
|
1430
1665
|
--prompt "..." Prompt to send when triggered
|
|
@@ -1438,6 +1673,7 @@ Examples:
|
|
|
1438
1673
|
rune new reviewer --role "Code reviewer, security focused"
|
|
1439
1674
|
rune run reviewer.rune "Review the latest commit"
|
|
1440
1675
|
rune pipe coder.rune reviewer.rune "Implement a login page"
|
|
1676
|
+
rune loop coder.rune reviewer.rune "Build a REST API" --until "no critical issues" --max-iterations 3 --auto
|
|
1441
1677
|
rune watch reviewer.rune --on git-commit --prompt "Review this commit"
|
|
1442
1678
|
rune watch monitor.rune --on cron --interval 5m --prompt "Check server health"
|
|
1443
1679
|
echo "Fix the bug in auth.ts" | rune run backend.rune
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openrune",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Persistent AI agents for Claude Code — build once, run forever.",
|
|
5
5
|
"keywords": ["ai", "agent", "claude", "desktop", "electron", "mcp", "claude-code", "toolkit", "automation"],
|
|
6
6
|
"repository": {
|