@mndrk/agx 1.4.1 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,8 +18,8 @@ agx -p "what does this function do?"
18
18
  # With persistent memory (auto-detected)
19
19
  agx claude -p "continue working on the todo app"
20
20
 
21
- # Auto-create task (for agents, non-interactive)
22
- agx claude --auto-task -p "Build a todo app with React"
21
+ # Autonomous mode - creates task and works until done
22
+ agx claude --autonomous -p "Build a todo app with React"
23
23
  ```
24
24
 
25
25
  ## Memory Integration
@@ -74,10 +74,9 @@ Agents control state via markers in their output:
74
74
  --interactive, -i Force interactive mode
75
75
  --mem Enable mem integration (auto-detected)
76
76
  --no-mem Disable mem integration
77
- --auto-task Auto-create task from prompt
77
+ --autonomous, -a Create task and run autonomously (starts daemon)
78
78
  --task <name> Specific task name
79
79
  --criteria <text> Success criterion (repeatable)
80
- --daemon Loop on [continue] marker
81
80
  ```
82
81
 
83
82
  ## Claude Code Plugin
@@ -100,8 +99,32 @@ agx config # Configuration menu
100
99
  agx status # Show current config
101
100
  agx skill # View LLM skill
102
101
  agx skill install # Install skill to Claude/Gemini
102
+
103
+ # Daemon management
104
+ agx daemon start # Start background daemon
105
+ agx daemon stop # Stop daemon
106
+ agx daemon status # Check if running
107
+ agx daemon logs # Show recent logs
103
108
  ```
104
109
 
110
+ ## Autonomous Mode
111
+
112
+ Start a task that runs autonomously until complete:
113
+
114
+ ```bash
115
+ agx claude --autonomous -p "Build a React todo app with auth"
116
+ # ✓ Created task: build-react-todo
117
+ # ✓ Mapped: ~/Projects/app → task/build-react-todo
118
+ # ✓ Daemon started (pid 12345)
119
+ # ✓ Autonomous mode: daemon will continue work every 15m
120
+ ```
121
+
122
+ The daemon:
123
+ - Runs in background (survives terminal close)
124
+ - Wakes every 15 minutes
125
+ - Continues work on active tasks
126
+ - Stops when task is `[done]` or `[blocked]`
127
+
105
128
  ## Loop Control
106
129
 
107
130
  The agent controls execution flow via markers:
@@ -0,0 +1,36 @@
1
+ # /agx:daemon - Manage Background Daemon
2
+
3
+ Control the agx daemon that runs autonomous tasks.
4
+
5
+ ## Usage
6
+ ```
7
+ /agx:daemon <action>
8
+ ```
9
+
10
+ ## Actions
11
+ - `start` - Start the daemon
12
+ - `stop` - Stop the daemon
13
+ - `status` - Check if running
14
+ - `logs` - Show recent logs
15
+
16
+ ## Implementation
17
+
18
+ ```bash
19
+ # Check status
20
+ agx daemon status
21
+
22
+ # Start if needed
23
+ agx daemon start
24
+
25
+ # View logs
26
+ agx daemon logs
27
+
28
+ # Stop when done
29
+ agx daemon stop
30
+ ```
31
+
32
+ The daemon:
33
+ - Runs in background (survives terminal close)
34
+ - Wakes every 15 minutes
35
+ - Continues work on active tasks
36
+ - Stops tasks when they output [done] or [blocked]
package/commands/spawn.md CHANGED
@@ -1,6 +1,6 @@
1
- # /agx:spawn - Spawn Background Agent
1
+ # /agx:spawn - Start Autonomous Task
2
2
 
3
- Spawn a background agent task with automatic wake schedule.
3
+ Spawn an autonomous agent task that runs until complete.
4
4
 
5
5
  ## Usage
6
6
  ```
@@ -15,17 +15,17 @@ Spawn a background agent task with automatic wake schedule.
15
15
  First, ensure you're in the correct project directory, then:
16
16
 
17
17
  ```bash
18
- agx claude --auto-task -p "$ARGUMENTS"
18
+ agx claude --autonomous -p "$ARGUMENTS"
19
19
  ```
20
20
 
21
21
  This will:
22
22
  1. Create a mem task branch
23
- 2. Set wake schedule (every 15m)
24
- 3. Start the agent working
23
+ 2. Start the agx daemon (if not running)
24
+ 3. Begin working on the task
25
+ 4. Daemon wakes every 15m to continue until [done]
25
26
 
26
- After spawning, install the wake cron:
27
+ Check status with:
27
28
  ```bash
28
- (crontab -l 2>/dev/null; mem cron export) | crontab -
29
+ agx daemon status
30
+ mem status
29
31
  ```
30
-
31
- Report the task name and confirm wake schedule is set.
package/index.js CHANGED
@@ -36,7 +36,7 @@ agx auto-detects \`~/.mem\` and loads context:
36
36
  agx claude -p "continue working"
37
37
 
38
38
  # Auto-create task (non-interactive, for agents)
39
- agx claude --auto-task -p "Build todo app"
39
+ agx claude --autonomous -p "Build todo app"
40
40
 
41
41
  # Explicit task with criteria
42
42
  agx claude --task todo-app \\
@@ -79,7 +79,7 @@ Use these in agent output to save state:
79
79
  | --yolo, -y | Skip permission prompts |
80
80
  | --mem | Enable mem (auto-detected) |
81
81
  | --no-mem | Disable mem |
82
- | --auto-task | Auto-create task from prompt |
82
+ | --autonomous, -a | Create task and run autonomously until done |
83
83
  | --task NAME | Specific task name |
84
84
  | --criteria "..." | Success criterion (repeatable) |
85
85
  | --daemon | Loop on [continue] marker |
@@ -148,7 +148,7 @@ function findMemDir(startDir = process.cwd()) {
148
148
  while (dir !== path.dirname(dir)) {
149
149
  const memDir = path.join(dir, '.mem');
150
150
  if (fs.existsSync(memDir) && fs.existsSync(path.join(memDir, '.git'))) {
151
- return memDir;
151
+ return { memDir, taskBranch: null, projectDir: dir, isLocal: true };
152
152
  }
153
153
  dir = path.dirname(dir);
154
154
  }
@@ -160,8 +160,17 @@ function findMemDir(startDir = process.cwd()) {
160
160
  if (fs.existsSync(indexFile)) {
161
161
  try {
162
162
  const index = JSON.parse(fs.readFileSync(indexFile, 'utf8'));
163
+ // Exact match
163
164
  if (index[startDir]) {
164
- return globalMem;
165
+ return { memDir: globalMem, taskBranch: index[startDir], projectDir: startDir, isLocal: false };
166
+ }
167
+ // Check parent directories (for monorepo/subdirectory usage)
168
+ let checkDir = startDir;
169
+ while (checkDir !== path.dirname(checkDir)) {
170
+ checkDir = path.dirname(checkDir);
171
+ if (index[checkDir]) {
172
+ return { memDir: globalMem, taskBranch: index[checkDir], projectDir: checkDir, isLocal: false };
173
+ }
165
174
  }
166
175
  } catch {}
167
176
  }
@@ -170,11 +179,22 @@ function findMemDir(startDir = process.cwd()) {
170
179
  return null;
171
180
  }
172
181
 
173
- // Load mem context
174
- function loadMemContext(memDir) {
182
+ // Load mem context for a specific task
183
+ function loadMemContext(memInfo) {
175
184
  try {
185
+ // If we know the task branch, switch to it first to ensure correct context
186
+ if (memInfo.taskBranch && !memInfo.isLocal) {
187
+ try {
188
+ execSync(`git checkout ${memInfo.taskBranch}`, {
189
+ cwd: memInfo.memDir,
190
+ stdio: ['pipe', 'pipe', 'pipe']
191
+ });
192
+ } catch {}
193
+ }
194
+
195
+ // Run mem context from the project directory
176
196
  const result = execSync('mem context', {
177
- cwd: path.dirname(memDir),
197
+ cwd: memInfo.projectDir,
178
198
  encoding: 'utf8',
179
199
  stdio: ['pipe', 'pipe', 'pipe']
180
200
  });
@@ -216,8 +236,9 @@ function parseMemMarkers(output) {
216
236
  }
217
237
 
218
238
  // Apply mem markers - returns control signals
219
- function applyMemMarkers(markers, memDir) {
220
- const workDir = path.dirname(memDir);
239
+ function applyMemMarkers(markers, memInfo) {
240
+ // Use project directory for commands (not parent of ~/.mem)
241
+ const workDir = memInfo.projectDir || path.dirname(memInfo.memDir || memInfo);
221
242
  const result = {
222
243
  approvals: [],
223
244
  shouldContinue: false,
@@ -291,8 +312,8 @@ function applyMemMarkers(markers, memDir) {
291
312
  }
292
313
 
293
314
  // Create subtasks from split markers
294
- function createSubtasks(splits, memDir) {
295
- const workDir = path.dirname(memDir);
315
+ function createSubtasks(splits, memInfo) {
316
+ const workDir = memInfo.projectDir || path.dirname(memInfo.memDir || memInfo);
296
317
 
297
318
  for (const split of splits) {
298
319
  try {
@@ -308,6 +329,169 @@ function createSubtasks(splits, memDir) {
308
329
  }
309
330
  }
310
331
 
332
+ // ==================== DAEMON ====================
333
+
334
+ const DAEMON_PID_FILE = path.join(process.env.HOME || process.env.USERPROFILE, '.agx', 'daemon.pid');
335
+ const DAEMON_LOG_FILE = path.join(process.env.HOME || process.env.USERPROFILE, '.agx', 'daemon.log');
336
+
337
+ function isDaemonRunning() {
338
+ try {
339
+ if (!fs.existsSync(DAEMON_PID_FILE)) return false;
340
+ const pid = parseInt(fs.readFileSync(DAEMON_PID_FILE, 'utf8').trim());
341
+ process.kill(pid, 0); // Check if process exists
342
+ return pid;
343
+ } catch {
344
+ return false;
345
+ }
346
+ }
347
+
348
+ function startDaemon() {
349
+ const existingPid = isDaemonRunning();
350
+ if (existingPid) {
351
+ console.log(`${c.dim}Daemon already running (pid ${existingPid})${c.reset}`);
352
+ return existingPid;
353
+ }
354
+
355
+ // Ensure .agx directory exists
356
+ const agxDir = path.dirname(DAEMON_PID_FILE);
357
+ if (!fs.existsSync(agxDir)) {
358
+ fs.mkdirSync(agxDir, { recursive: true });
359
+ }
360
+
361
+ // Spawn daemon process
362
+ const agxPath = process.argv[1]; // Current script path
363
+ const daemon = spawn(process.execPath, [agxPath, 'daemon', '--run'], {
364
+ detached: true,
365
+ stdio: ['ignore',
366
+ fs.openSync(DAEMON_LOG_FILE, 'a'),
367
+ fs.openSync(DAEMON_LOG_FILE, 'a')
368
+ ],
369
+ env: { ...process.env, AGX_DAEMON: '1' }
370
+ });
371
+
372
+ daemon.unref();
373
+ fs.writeFileSync(DAEMON_PID_FILE, String(daemon.pid));
374
+
375
+ console.log(`${c.green}✓${c.reset} Daemon started (pid ${daemon.pid})`);
376
+ console.log(`${c.dim} Logs: ${DAEMON_LOG_FILE}${c.reset}`);
377
+
378
+ return daemon.pid;
379
+ }
380
+
381
+ function stopDaemon() {
382
+ const pid = isDaemonRunning();
383
+ if (!pid) {
384
+ console.log(`${c.yellow}Daemon not running${c.reset}`);
385
+ return false;
386
+ }
387
+
388
+ try {
389
+ process.kill(pid, 'SIGTERM');
390
+ fs.unlinkSync(DAEMON_PID_FILE);
391
+ console.log(`${c.green}✓${c.reset} Daemon stopped (pid ${pid})`);
392
+ return true;
393
+ } catch (err) {
394
+ console.error(`${c.red}Failed to stop daemon:${c.reset} ${err.message}`);
395
+ return false;
396
+ }
397
+ }
398
+
399
+ // Parse wake pattern to milliseconds (e.g., "every 15m" → 900000)
400
+ function parseWakeInterval(pattern) {
401
+ if (!pattern) return null;
402
+
403
+ const match = pattern.match(/every\s+(\d+)\s*(m|min|h|hr|hour)/i);
404
+ if (match) {
405
+ const value = parseInt(match[1]);
406
+ const unit = match[2].toLowerCase();
407
+ if (unit.startsWith('h')) return value * 60 * 60 * 1000;
408
+ return value * 60 * 1000; // minutes
409
+ }
410
+ return null;
411
+ }
412
+
413
+ async function runDaemon() {
414
+ console.log(`[${new Date().toISOString()}] Daemon starting...`);
415
+
416
+ const DEFAULT_WAKE_INTERVAL = 15 * 60 * 1000; // 15 minutes fallback
417
+ const memDir = path.join(process.env.HOME || process.env.USERPROFILE, '.mem');
418
+
419
+ // Read wake interval from mem state (use shortest interval across all tasks)
420
+ function getWakeInterval() {
421
+ try {
422
+ const indexFile = path.join(memDir, 'index.json');
423
+ if (!fs.existsSync(indexFile)) return DEFAULT_WAKE_INTERVAL;
424
+
425
+ const index = JSON.parse(fs.readFileSync(indexFile, 'utf8'));
426
+ let minInterval = DEFAULT_WAKE_INTERVAL;
427
+
428
+ for (const taskBranch of Object.values(index)) {
429
+ try {
430
+ execSync(`git checkout ${taskBranch}`, { cwd: memDir, stdio: 'ignore' });
431
+ const state = fs.readFileSync(path.join(memDir, 'state.md'), 'utf8');
432
+ const wakeMatch = state.match(/^wake:\s*(.+)$/m);
433
+ if (wakeMatch) {
434
+ const interval = parseWakeInterval(wakeMatch[1]);
435
+ if (interval && interval < minInterval) minInterval = interval;
436
+ }
437
+ } catch {}
438
+ }
439
+ return minInterval;
440
+ } catch {
441
+ return DEFAULT_WAKE_INTERVAL;
442
+ }
443
+ }
444
+
445
+ const tick = async () => {
446
+ console.log(`[${new Date().toISOString()}] Daemon tick - checking tasks...`);
447
+
448
+ const indexFile = path.join(memDir, 'index.json');
449
+
450
+ if (!fs.existsSync(indexFile)) {
451
+ console.log(`[${new Date().toISOString()}] No tasks found`);
452
+ return;
453
+ }
454
+
455
+ const index = JSON.parse(fs.readFileSync(indexFile, 'utf8'));
456
+
457
+ for (const [projectDir, taskBranch] of Object.entries(index)) {
458
+ if (!fs.existsSync(projectDir)) continue;
459
+
460
+ // Check if task is active
461
+ try {
462
+ execSync(`git checkout ${taskBranch}`, { cwd: memDir, stdio: 'ignore' });
463
+ const state = fs.readFileSync(path.join(memDir, 'state.md'), 'utf8');
464
+
465
+ if (state.includes('status: active')) {
466
+ console.log(`[${new Date().toISOString()}] Continuing task: ${taskBranch} in ${projectDir}`);
467
+
468
+ // Run agx continue
469
+ try {
470
+ execSync(`agx claude -y -p "continue"`, {
471
+ cwd: projectDir,
472
+ stdio: 'inherit',
473
+ timeout: 10 * 60 * 1000 // 10 min timeout
474
+ });
475
+ } catch (err) {
476
+ console.log(`[${new Date().toISOString()}] Task ${taskBranch} error: ${err.message}`);
477
+ }
478
+ }
479
+ } catch (err) {
480
+ console.log(`[${new Date().toISOString()}] Error checking ${taskBranch}: ${err.message}`);
481
+ }
482
+ }
483
+ };
484
+
485
+ // Initial tick
486
+ await tick();
487
+
488
+ // Get interval from mem (with fallback) and schedule recurring ticks
489
+ const wakeInterval = getWakeInterval();
490
+ setInterval(tick, wakeInterval);
491
+
492
+ console.log(`[${new Date().toISOString()}] Daemon running, wake interval: ${wakeInterval / 1000 / 60}m`);
493
+ }
494
+
311
495
  // Handle approval prompts
312
496
  async function handleApprovals(approvals) {
313
497
  if (approvals.length === 0) return true;
@@ -906,6 +1090,48 @@ async function checkOnboarding() {
906
1090
  return true;
907
1091
  }
908
1092
 
1093
+ // Daemon commands
1094
+ if (cmd === 'daemon') {
1095
+ const subcmd = args[1];
1096
+ if (subcmd === 'start') {
1097
+ startDaemon();
1098
+ process.exit(0);
1099
+ } else if (subcmd === 'stop') {
1100
+ stopDaemon();
1101
+ process.exit(0);
1102
+ } else if (subcmd === 'status') {
1103
+ const pid = isDaemonRunning();
1104
+ if (pid) {
1105
+ console.log(`${c.green}Daemon running${c.reset} (pid ${pid})`);
1106
+ console.log(`${c.dim}Logs: ${DAEMON_LOG_FILE}${c.reset}`);
1107
+ } else {
1108
+ console.log(`${c.yellow}Daemon not running${c.reset}`);
1109
+ }
1110
+ process.exit(0);
1111
+ } else if (subcmd === 'logs') {
1112
+ if (fs.existsSync(DAEMON_LOG_FILE)) {
1113
+ const logs = fs.readFileSync(DAEMON_LOG_FILE, 'utf8');
1114
+ console.log(logs.split('\n').slice(-50).join('\n'));
1115
+ } else {
1116
+ console.log(`${c.dim}No logs yet${c.reset}`);
1117
+ }
1118
+ process.exit(0);
1119
+ } else if (subcmd === '--run') {
1120
+ // Internal: actually run the daemon loop
1121
+ await runDaemon();
1122
+ return true; // Never exits
1123
+ } else {
1124
+ console.log(`${c.bold}agx daemon${c.reset} - Background task runner\n`);
1125
+ console.log(`Commands:`);
1126
+ console.log(` agx daemon start Start the daemon`);
1127
+ console.log(` agx daemon stop Stop the daemon`);
1128
+ console.log(` agx daemon status Check if running`);
1129
+ console.log(` agx daemon logs Show recent logs`);
1130
+ process.exit(0);
1131
+ }
1132
+ return true;
1133
+ }
1134
+
909
1135
  // Login command
910
1136
  if (cmd === 'login') {
911
1137
  const provider = args[1];
@@ -1105,7 +1331,7 @@ const options = {
1105
1331
  mcp: null,
1106
1332
  mem: false,
1107
1333
  memDir: null,
1108
- autoTask: false,
1334
+ autonomous: false,
1109
1335
  taskName: null,
1110
1336
  criteria: [],
1111
1337
  daemon: false,
@@ -1166,9 +1392,12 @@ for (let i = 0; i < processedArgs.length; i++) {
1166
1392
  case '--no-mem':
1167
1393
  options.mem = false;
1168
1394
  break;
1169
- case '--auto-task':
1170
- options.autoTask = true;
1395
+ case '--autonomous':
1396
+ case '--auto':
1397
+ case '-a':
1398
+ options.autonomous = true;
1171
1399
  options.mem = true;
1400
+ options.yolo = true; // Autonomous = unattended, skip prompts
1172
1401
  break;
1173
1402
  case '--task':
1174
1403
  if (nextArg && !nextArg.startsWith('-')) {
@@ -1273,14 +1502,15 @@ translatedArgs.push(...rawArgs);
1273
1502
  // ==================== MEM INTEGRATION ====================
1274
1503
 
1275
1504
  // Auto-detect mem if .mem exists (unless --no-mem)
1276
- let memDir = options.mem !== false ? findMemDir() : null;
1277
- if (memDir && options.mem !== false) {
1505
+ let memInfo = options.mem !== false ? findMemDir() : null;
1506
+ if (memInfo && options.mem !== false) {
1278
1507
  options.mem = true;
1279
- options.memDir = memDir;
1508
+ options.memInfo = memInfo;
1509
+ options.memDir = memInfo.memDir; // For backwards compat
1280
1510
  }
1281
1511
 
1282
- // Auto-create task if --auto-task or --task specified but no mem found
1283
- if ((options.autoTask || options.taskName) && !options.memDir && finalPrompt) {
1512
+ // Auto-create task if --autonomous or --task specified but no mem found
1513
+ if ((options.autonomous || options.taskName) && !options.memInfo && finalPrompt) {
1284
1514
  const taskName = options.taskName || finalPrompt
1285
1515
  .toLowerCase()
1286
1516
  .replace(/[^a-z0-9\s]/g, '')
@@ -1336,33 +1566,32 @@ if ((options.autoTask || options.taskName) && !options.memDir && finalPrompt) {
1336
1566
  fs.writeFileSync(indexFile, JSON.stringify(index, null, 2));
1337
1567
 
1338
1568
  options.memDir = centralMem;
1569
+ options.memInfo = { memDir: centralMem, taskBranch: branch, projectDir: process.cwd(), isLocal: false };
1339
1570
  console.log(`${c.green}✓${c.reset} Created task: ${c.bold}${taskName}${c.reset}`);
1340
1571
  console.log(`${c.green}✓${c.reset} Mapped: ${c.dim}${process.cwd()} → ${branch}${c.reset}`);
1341
1572
 
1342
- // Auto-set wake schedule for new tasks with proper command
1343
- // Detect agx path dynamically for cron (no PATH in cron env)
1573
+ // Auto-set wake schedule
1344
1574
  try {
1345
- const projectDir = process.cwd();
1346
- let agxPath = 'agx';
1347
- try {
1348
- agxPath = execSync('which agx', { encoding: 'utf8' }).trim();
1349
- } catch {}
1350
- const wakeCmd = `cd ${projectDir} && ${agxPath} claude -y -p "continue"`;
1351
- execSync(`mem wake "every 15m" --run "${wakeCmd}"`, { cwd: process.cwd(), stdio: 'ignore' });
1352
- console.log(`${c.green}✓${c.reset} Wake: ${c.dim}every 15m (until done)${c.reset}`);
1353
- console.log(`${c.dim} Run: agx claude -y -p "continue"${c.reset}\n`);
1575
+ execSync(`mem wake "every 15m"`, { cwd: process.cwd(), stdio: 'ignore' });
1354
1576
  } catch {}
1355
1577
 
1578
+ // Start daemon for autonomous mode
1579
+ if (options.autonomous) {
1580
+ startDaemon();
1581
+ console.log(`${c.green}✓${c.reset} Autonomous mode: daemon will continue work every 15m\n`);
1582
+ }
1583
+
1356
1584
  } catch (err) {
1357
1585
  console.error(`${c.yellow}Warning: Could not create task:${c.reset} ${err.message}`);
1358
1586
  }
1359
1587
  }
1360
1588
 
1361
1589
  // Prepend mem context to prompt if mem is enabled
1362
- if (options.mem && options.memDir && finalPrompt) {
1363
- const context = loadMemContext(options.memDir);
1590
+ if (options.mem && options.memInfo && finalPrompt) {
1591
+ const context = loadMemContext(options.memInfo);
1364
1592
  if (context) {
1365
- console.log(`${c.dim}[mem] Loaded context from ${options.memDir}${c.reset}\n`);
1593
+ const taskInfo = options.memInfo.taskBranch || 'local';
1594
+ console.log(`${c.dim}[mem] Loaded context: ${taskInfo} (${options.memInfo.projectDir})${c.reset}\n`);
1366
1595
 
1367
1596
  // Prepend context to prompt with full marker documentation
1368
1597
  const augmentedPrompt = `## Current Context (from mem)\n\n${context}\n\n## Task\n\n${finalPrompt}\n\n## Instructions\n\nYou are continuing work on this task. Review the context above, then continue where you left off.\n\n## Output Markers\n\nUse these markers to save state (will be parsed automatically):\n\n- [checkpoint: message] - save progress point\n- [learn: insight] - record a learning \n- [next: step] - set what to work on next\n- [criteria: N] - mark criterion #N complete\n- [split: name "goal"] - break into subtask\n\nStopping markers (only use when needed):\n- [done] - task complete (all criteria met)\n- [blocked: reason] - need human help, cannot proceed\n- [approve: question] - need human approval before continuing\n\nThe default is to keep working. You will wake again in 15 minutes to continue.`;
@@ -1398,11 +1627,11 @@ if (options.mem && options.memDir) {
1398
1627
 
1399
1628
  if (markers.length > 0) {
1400
1629
  console.log(`\n${c.dim}[mem] Processing markers...${c.reset}`);
1401
- const result = applyMemMarkers(markers, options.memDir);
1630
+ const result = applyMemMarkers(markers, options.memInfo || { memDir: options.memDir, projectDir: process.cwd() });
1402
1631
 
1403
1632
  // Create subtasks if any
1404
1633
  if (result.splits.length > 0) {
1405
- createSubtasks(result.splits, options.memDir);
1634
+ createSubtasks(result.splits, options.memInfo || { memDir: options.memDir, projectDir: process.cwd() });
1406
1635
  }
1407
1636
 
1408
1637
  // Handle approvals
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mndrk/agx",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "description": "Unified AI Agent Wrapper for Gemini, Claude, and Ollama",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -1,13 +1,13 @@
1
1
  # agx - Unified AI Agent Wrapper
2
2
 
3
- Use `agx` to run AI agents (Claude Code, Gemini, Ollama) with persistent memory integration. Spawn background tasks that wake automatically and continue working.
3
+ Use `agx` to run AI agents (Claude Code, Gemini, Ollama) with persistent memory integration. Spawn autonomous tasks that work in the background until complete.
4
4
 
5
5
  ## When to Use
6
6
 
7
- - **Spawning background agents** for long-running tasks
8
- - **Auto-task creation** with wake schedules
7
+ - **Autonomous agents** for long-running tasks
8
+ - **Background work** that continues without supervision
9
9
  - **Running different AI providers** with unified interface
10
- - **Autonomous work loops** that continue until done
10
+ - **Persistent memory** across sessions
11
11
 
12
12
  ## Basic Usage
13
13
 
@@ -17,41 +17,43 @@ agx gemini -p "prompt" # Run Gemini
17
17
  agx ollama -p "prompt" # Run Ollama (local)
18
18
  ```
19
19
 
20
- ## Auto-Task Mode (Recommended)
20
+ ## Autonomous Mode (Recommended)
21
21
 
22
- Create a task with automatic wake schedule:
22
+ Start a task that runs autonomously until complete:
23
23
 
24
24
  ```bash
25
25
  cd ~/Projects/my-app
26
- agx claude --auto-task -p "Build a React todo app with auth"
26
+ agx claude --autonomous -p "Build a React todo app with auth"
27
27
  # ✓ Created task: build-react-todo
28
28
  # ✓ Mapped: ~/Projects/my-app → task/build-react-todo
29
- # ✓ Wake: every 15m (until done)
29
+ # ✓ Daemon started (pid 12345)
30
+ # ✓ Autonomous mode: daemon will continue work every 15m
30
31
  ```
31
32
 
32
33
  This:
33
34
  1. Creates a mem task branch
34
- 2. Sets wake schedule (every 15m)
35
- 3. Installs cron to continue automatically
36
- 4. Agent works until [done] or [blocked]
35
+ 2. Starts the agx daemon (if not running)
36
+ 3. Daemon wakes every 15m to continue work
37
+ 4. Runs until agent outputs [done] or [blocked]
37
38
 
38
- ## Wake Loop
39
+ ## Daemon Management
39
40
 
40
- ```
41
- WAKE (cron) → Load context → Agent works → Save state → SLEEP
42
-
43
- repeat until [done]
44
- ```
45
-
46
- Install the wake schedule:
47
41
  ```bash
48
- mem cron export # View entry
49
- (crontab -l; mem cron export) | crontab - # Install
42
+ agx daemon start # Start background daemon
43
+ agx daemon stop # Stop daemon
44
+ agx daemon status # Check if running
45
+ agx daemon logs # Show recent logs
50
46
  ```
51
47
 
48
+ The daemon:
49
+ - Runs in background (survives terminal close)
50
+ - Wakes every 15 minutes
51
+ - Continues work on active tasks
52
+ - Stops when task is [done] or [blocked]
53
+
52
54
  ## Output Markers
53
55
 
54
- Use these in agent output to control the loop:
56
+ Use these in agent output to control state:
55
57
 
56
58
  ### Progress (parsed automatically)
57
59
  ```
@@ -63,17 +65,12 @@ Use these in agent output to control the loop:
63
65
 
64
66
  ### Stopping Markers
65
67
  ```
66
- [done] # Task complete, clear wake, stop
67
- [blocked: reason] # Need human help, pause loop
68
+ [done] # Task complete, stop
69
+ [blocked: reason] # Need human help, pause
68
70
  [approve: question] # Need approval, wait
69
71
  [pause] # Stop, resume on next wake
70
72
  ```
71
73
 
72
- ### Loop Control
73
- ```
74
- [continue] # Keep going (--daemon mode loops locally)
75
- ```
76
-
77
74
  **Default behavior:** Keep working. Only output stopping markers when needed.
78
75
 
79
76
  ## Provider Aliases
@@ -87,11 +84,9 @@ Use these in agent output to control the loop:
87
84
  ## Common Flags
88
85
 
89
86
  ```bash
90
- --auto-task # Auto-create task from prompt
87
+ --autonomous, -a # Create task and run autonomously (starts daemon)
91
88
  --task NAME # Specific task name
92
89
  --criteria "..." # Success criterion (repeatable)
93
- --daemon # Loop on [continue] marker
94
- --until-done # Keep running until [done]
95
90
  -y # Skip confirmations
96
91
  ```
97
92
 
@@ -102,18 +97,18 @@ Use these in agent output to control the loop:
102
97
  agx claude -p "Explain this error" -y
103
98
  ```
104
99
 
105
- ### Background task with wake
100
+ ### Autonomous task
106
101
  ```bash
107
102
  cd ~/Projects/api
108
- agx claude --auto-task -p "Add user authentication with JWT"
109
- # Agent works, saves progress, wakes every 15m to continue
103
+ agx claude --autonomous -p "Add user authentication with JWT"
104
+ # Daemon continues work every 15m until done
110
105
  ```
111
106
 
112
107
  ### Check on a running task
113
108
  ```bash
114
- mem status # Quick summary
109
+ agx daemon status # Check daemon
110
+ mem status # Task summary
115
111
  mem progress # % complete
116
- mem context # Full state dump
117
112
  ```
118
113
 
119
114
  ### Manual continue