atris 3.57.4 → 3.58.5

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.
Files changed (174) hide show
  1. package/README.md +12 -1
  2. package/atris/skills/clawhub/member-runtime/SKILL.md +9 -9
  3. package/atris/skills/create-member/SKILL.md +16 -13
  4. package/atris/skills/design/SKILL.md +27 -4
  5. package/atris/skills/engines/SKILL.md +55 -12
  6. package/atris/skills/x-search/SKILL.md +8 -6
  7. package/atris/skills/youtube/SKILL.md +37 -8
  8. package/atris/team/brainstormer/MEMBER.md +2 -2
  9. package/atris/team/executor/MEMBER.md +3 -3
  10. package/atris/team/launcher/MEMBER.md +4 -4
  11. package/atris/team/navigator/MEMBER.md +3 -3
  12. package/atris/team/researcher/MEMBER.md +2 -2
  13. package/atris/team/validator/MEMBER.md +1 -1
  14. package/atris.md +14 -0
  15. package/ax +153 -23
  16. package/bin/atris.js +78 -30
  17. package/commands/aeo.js +4 -4
  18. package/commands/agents.js +1 -1
  19. package/commands/align.js +12 -12
  20. package/commands/analytics.js +3 -3
  21. package/commands/app.js +5 -5
  22. package/commands/ask.js +175 -0
  23. package/commands/auth.js +7 -7
  24. package/commands/autoland.js +29 -5
  25. package/commands/autopilot-front.js +6 -6
  26. package/commands/autopilot.js +90 -90
  27. package/commands/avail.js +5 -5
  28. package/commands/bench.js +63 -1
  29. package/commands/browse.js +2 -2
  30. package/commands/business.js +12 -12
  31. package/commands/card.js +2 -2
  32. package/commands/clean.js +13 -13
  33. package/commands/close.js +3 -3
  34. package/commands/compile.js +13 -13
  35. package/commands/computer.js +94 -27
  36. package/commands/console.js +5 -5
  37. package/commands/decide.js +1 -1
  38. package/commands/deck.js +9 -9
  39. package/commands/drive.js +4 -4
  40. package/commands/engine.js +173 -19
  41. package/commands/errors.js +3 -3
  42. package/commands/experiments.js +18 -1
  43. package/commands/feed.js +2 -2
  44. package/commands/feedback.js +4 -4
  45. package/commands/fleet.js +12 -12
  46. package/commands/game.js +1 -1
  47. package/commands/guide.js +49 -0
  48. package/commands/improve.js +19 -17
  49. package/commands/init.js +67 -19
  50. package/commands/interview.js +7 -7
  51. package/commands/land.js +40 -15
  52. package/commands/learn.js +12 -12
  53. package/commands/lesson.js +2 -2
  54. package/commands/log.js +1 -1
  55. package/commands/loops.js +4 -4
  56. package/commands/member.js +75 -50
  57. package/commands/mission.js +90 -82
  58. package/commands/one-lap.js +1 -1
  59. package/commands/pack.js +74 -8
  60. package/commands/plugin.js +6 -6
  61. package/commands/probe.js +9 -9
  62. package/commands/pull.js +35 -35
  63. package/commands/pulse.js +1 -1
  64. package/commands/push.js +21 -21
  65. package/commands/rainmaker.js +1 -1
  66. package/commands/recap.js +7 -7
  67. package/commands/reel.js +2 -2
  68. package/commands/release.js +3 -3
  69. package/commands/report.js +1 -1
  70. package/commands/review.js +5 -5
  71. package/commands/revisions.js +1 -1
  72. package/commands/run.js +1 -1
  73. package/commands/scout.js +3 -3
  74. package/commands/security-review.js +7 -7
  75. package/commands/serve.js +9 -9
  76. package/commands/setup.js +1 -1
  77. package/commands/sign.js +4 -4
  78. package/commands/signup.js +4 -4
  79. package/commands/site.js +8 -3
  80. package/commands/skill.js +6 -6
  81. package/commands/slop.js +18 -18
  82. package/commands/social.js +3 -3
  83. package/commands/soul.js +14 -14
  84. package/commands/spaceship.js +1 -1
  85. package/commands/status.js +2 -2
  86. package/commands/strings.js +13 -13
  87. package/commands/study.js +4 -4
  88. package/commands/sync.js +8 -8
  89. package/commands/task.js +50 -25
  90. package/commands/teach.js +2 -2
  91. package/commands/team.js +1 -1
  92. package/commands/theme.js +2 -2
  93. package/commands/tree.js +34 -0
  94. package/commands/truth.js +7 -7
  95. package/commands/verify.js +12 -12
  96. package/commands/visualize.js +2 -2
  97. package/commands/workflow.js +97 -40
  98. package/commands/worktree.js +1 -1
  99. package/commands/write.js +9 -9
  100. package/commands/x-search.js +89 -17
  101. package/commands/xp.js +6 -3
  102. package/commands/youtube.js +601 -48
  103. package/lib/accept-verify-gate.js +3 -3
  104. package/lib/activity-stream.js +1 -1
  105. package/lib/auto-accept-certified.js +28 -12
  106. package/lib/autoland.js +6 -6
  107. package/lib/bench/engines.js +59 -8
  108. package/lib/bench/report.js +1 -1
  109. package/lib/bench/runner.js +204 -5
  110. package/lib/bench/tree-render.js +76 -0
  111. package/lib/card.js +1 -1
  112. package/lib/chat-log-scan.js +1 -1
  113. package/lib/claude-boot-block.js +2 -0
  114. package/lib/deck-compose.js +1 -1
  115. package/lib/deck-history.js +2 -2
  116. package/lib/deck-layout.js +1 -1
  117. package/lib/deck-review.js +5 -5
  118. package/lib/deck-schema.js +1 -1
  119. package/lib/default-verifier.js +1 -1
  120. package/lib/developer-api.js +3 -0
  121. package/lib/engine-ask.js +45 -7
  122. package/lib/engine-registry.js +15 -2
  123. package/lib/file-ops.js +1 -1
  124. package/lib/fleet.js +71 -35
  125. package/lib/html-render.js +1 -1
  126. package/lib/intents.js +172 -0
  127. package/lib/journal.js +1 -1
  128. package/lib/known-commands.js +2 -2
  129. package/lib/land-green.js +364 -0
  130. package/lib/lesson-contradiction.js +2 -2
  131. package/lib/lesson-preflight.js +1 -1
  132. package/lib/manifest.js +5 -5
  133. package/lib/member-alive.js +9 -5
  134. package/lib/memory-view.js +3 -3
  135. package/lib/mission-protected-lane.js +1 -1
  136. package/lib/mission-root.js +2 -2
  137. package/lib/orb-context.js +10 -10
  138. package/lib/pack-capabilities.js +861 -3
  139. package/lib/permission-grants.js +2 -2
  140. package/lib/policy-lessons.js +6 -6
  141. package/lib/pulse.js +8 -8
  142. package/lib/receipt-evidence.js +1 -1
  143. package/lib/reel.js +1 -1
  144. package/lib/review-integrity.js +1 -1
  145. package/lib/runner-command.js +35 -5
  146. package/lib/scorecard.js +4 -4
  147. package/lib/security-scan.js +5 -5
  148. package/lib/self-drive.js +1 -1
  149. package/lib/site-publish.js +372 -0
  150. package/lib/site.js +1 -1
  151. package/lib/slides-deck.js +2 -2
  152. package/lib/state-detection.js +2 -2
  153. package/lib/sync-telemetry.js +2 -2
  154. package/lib/task-db.js +17 -10
  155. package/lib/task-explanation.js +1 -1
  156. package/lib/task-proof.js +2 -2
  157. package/lib/task-receipt.js +3 -3
  158. package/lib/theme.js +12 -12
  159. package/lib/todo-fallback.js +3 -3
  160. package/lib/todo-sections.js +1 -1
  161. package/lib/tree-hash.js +79 -0
  162. package/lib/usage.js +1 -1
  163. package/lib/wish-delegate.js +1 -1
  164. package/lib/workspace-safety.js +4 -4
  165. package/lib/workspace-scaffold.js +3 -3
  166. package/package.json +1 -1
  167. package/scripts/det/concierge-bakeoff.sh +26 -0
  168. package/scripts/det/ytquote-repair.js +0 -1
  169. package/scripts/det/ytrail-race.js +0 -5
  170. package/scripts/member-operate.mjs +52 -14
  171. package/scripts/outbound-artifact-gate.js +0 -3
  172. package/utils/auth.js +0 -3
  173. package/utils/config.js +0 -1
  174. package/scripts/det/checklist-score.js +0 -191
package/commands/log.js CHANGED
@@ -119,7 +119,7 @@ function logAtris() {
119
119
  }
120
120
 
121
121
  console.log(`┌─────────────────────────────────────────────────────────┐`);
122
- console.log(`│ Daily Log ${dateFormatted} [type "exit" to quit] │`);
122
+ console.log(`│ Daily Log, ${dateFormatted} [type "exit" to quit] │`);
123
123
  console.log(`└─────────────────────────────────────────────────────────┘`);
124
124
  console.log('');
125
125
 
package/commands/loops.js CHANGED
@@ -308,7 +308,7 @@ function auditLoops(cwd = process.cwd()) {
308
308
  console.log('No atris/loops directory found.');
309
309
  console.log('Run: atris loops init');
310
310
  console.log('');
311
- console.log('SELF-IMPROVING: NOT YET 1 open');
311
+ console.log('SELF-IMPROVING: NOT YET, 1 open');
312
312
  return 1;
313
313
  }
314
314
 
@@ -320,7 +320,7 @@ function auditLoops(cwd = process.cwd()) {
320
320
  console.log('No loop files found in atris/loops.');
321
321
  console.log('Run: atris loops init');
322
322
  console.log('');
323
- console.log('SELF-IMPROVING: NOT YET 1 open');
323
+ console.log('SELF-IMPROVING: NOT YET, 1 open');
324
324
  return 1;
325
325
  }
326
326
 
@@ -352,7 +352,7 @@ function auditLoops(cwd = process.cwd()) {
352
352
  console.log('SELF-IMPROVING: YES');
353
353
  return 0;
354
354
  }
355
- console.log(`SELF-IMPROVING: NOT YET ${open} open`);
355
+ console.log(`SELF-IMPROVING: NOT YET, ${open} open`);
356
356
  return 1;
357
357
  }
358
358
 
@@ -382,7 +382,7 @@ function showLoopsHelp() {
382
382
  }
383
383
 
384
384
  function loopsCommand(subcommand, ...args) {
385
- // `loops <sub> --help` is a help request, not a run tick/start/stop/init
385
+ // `loops <sub> --help` is a help request, not a run, tick/start/stop/init
386
386
  // mutate loop state, so never execute a subcommand just to show usage.
387
387
  if (subcommand === '--help' || subcommand === '-h' || subcommand === 'help'
388
388
  || args.includes('--help') || args.includes('-h')) {
@@ -215,7 +215,7 @@ function memberPaths(name) {
215
215
  // Steering signals live in the workspace's single .atris/state store. Resolve
216
216
  // the shared workspace root (spine -> git -> cwd) so a member run from a
217
217
  // subdirectory reads steering from the real store instead of a nonexistent
218
- // nested .atris the same resolver the mission/task/usage/autopilot state
218
+ // nested .atris, the same resolver the mission/task/usage/autopilot state
219
219
  // uses. (teamDir markdown discovery is a separate cwd concern, filed.)
220
220
  const workspaceRoot = require('../lib/mission-root').resolveWorkspaceRoot(process.cwd());
221
221
  return {
@@ -482,7 +482,7 @@ function memberRunRunnableMissionId(candidateId, missionMap) {
482
482
 
483
483
  function memberRunOwnedActiveMissionId(name, missionMap) {
484
484
  // Discovery fallback when the member's own pointers are stale: resume the
485
- // member's newest moving mission. ready is excluded it waits for review.
485
+ // member's newest moving mission. ready is excluded, it waits for review.
486
486
  const owner = String(name || '').trim().toLowerCase();
487
487
  const candidates = Array.from(missionMap.values())
488
488
  .filter((mission) => String(mission?.owner || '').trim().toLowerCase() === owner)
@@ -833,7 +833,7 @@ function buildMemberRunStartArgs(owner, missionText, args = [], cwd = process.cw
833
833
  pushFlagValue(startArgs, args, '--hours');
834
834
  pushFlagValue(startArgs, args, '--base');
835
835
  // A member-run mission is driven immediately by its runner, not parked on
836
- // the queue so the mission-start verifier gate (built for parked planning
836
+ // the queue, so the mission-start verifier gate (built for parked planning
837
837
  // wishes) would only kill autonomous legs like autopilot's "member chooses
838
838
  // useful work". When the caller named no verifier, opt out explicitly.
839
839
  if (hasFlag(args, '--no-verify') || !readFlag(args, '--verify', '')) {
@@ -847,7 +847,7 @@ function buildMemberRunStartArgs(owner, missionText, args = [], cwd = process.cw
847
847
  pushFlagWhenPresent(startArgs, args, '--stop-when-done');
848
848
  // Default to an isolated worktree only when there is a git repo to cut it
849
849
  // from. A plain (non-git) workspace would fail every mission start with
850
- // "fatal: not a git repository" degrade to the shared checkout instead.
850
+ // "fatal: not a git repository", degrade to the shared checkout instead.
851
851
  if (!hasFlag(args, '--shared-checkout') && !hasFlag(args, '--no-worktree') && insideGitRepo(cwd)) {
852
852
  startArgs.push('--worktree');
853
853
  }
@@ -881,7 +881,7 @@ function startMemberRunMission(name, missionText, args = []) {
881
881
  }
882
882
  }
883
883
 
884
- // atris member ping <name> "<message>" talk to a busy member mid-run.
884
+ // atris member ping <name> "<message>": talk to a busy member mid-run.
885
885
  // Two delivery lanes: the member's most recently touched live mission
886
886
  // (including --worktree missions in sibling checkouts), whose next tick
887
887
  // consumes the note, and the member's claimed task dialogue, which task-loop
@@ -958,8 +958,8 @@ function memberPing(name, ...args) {
958
958
  task_id: taskNote ? taskNote.task_id : null,
959
959
  }));
960
960
  } else {
961
- if (mission) console.log(`pinged ${mission.id} the next tick reads it (${pendingPings} unread).`);
962
- if (taskNote) console.log(`pinged task ${taskNote.task_id} dialogue ${name} reads it on the next step.`);
961
+ if (mission) console.log(`pinged ${mission.id}, the next tick reads it (${pendingPings} unread).`);
962
+ if (taskNote) console.log(`pinged task ${taskNote.task_id} dialogue, ${name} reads it on the next step.`);
963
963
  }
964
964
  return { mission, task_note: taskNote };
965
965
  }
@@ -2665,6 +2665,7 @@ function buildMemberAliveCronScript(name, args = [], paths = memberLoopPaths(nam
2665
2665
  '--json',
2666
2666
  ...(hasFlag(args, '--execute') ? ['--execute'] : []),
2667
2667
  ...(hasFlag(args, '--confirm-autonomy-policy') ? ['--confirm-autonomy-policy'] : []),
2668
+ ...(hasFlag(args, '--shared-checkout') ? ['--shared-checkout'] : []),
2668
2669
  ];
2669
2670
  const agent = String(readFlag(args, '--agent', '') || '').trim();
2670
2671
  const model = String(readFlag(args, '--model', '') || '').trim();
@@ -3027,7 +3028,7 @@ function collectAutoImproverLogSignals(root) {
3027
3028
  ].filter((candidate) => fs.existsSync(candidate));
3028
3029
  const passLessonText = safeReadText(path.join(root, 'atris', 'lessons.md'), 500000)
3029
3030
  .split(/\r?\n/)
3030
- .filter((line) => /\s+pass\s+—/.test(line))
3031
+ .filter((line) => /\s+pass\s*[-\u2014:,]/.test(line))
3031
3032
  .join('\n');
3032
3033
  const failureRegex = /\b(error|failed|failure|blocked|timeout|regression|crash|missing proof|naraka|suffering)\b/i;
3033
3034
  const unclearRegex = /\b(tbd|unclear|unknown|needs user|needs owner|needs proof|no next|blocked)\b/i;
@@ -3046,6 +3047,15 @@ function collectAutoImproverLogSignals(root) {
3046
3047
  || /^atris\/team\/[^/]+\/goals\.(md|json)$/.test(relative)
3047
3048
  || relative === 'atris/wiki/log.md';
3048
3049
  if (!isRuntimeLog) continue;
3050
+ // Only scan logs from the last 7 days. Historical log lines keep
3051
+ // triggering false-positive findings long after their root cause is
3052
+ // fixed (e.g. "goal-from-mission blocked" from July when MISSION.md
3053
+ // was repaired in August). Old evidence stays on disk for audits;
3054
+ // it just stops feeding the pain score, so pain can actually drop.
3055
+ if (logDate && isRuntimeLog) {
3056
+ const logAgeDays = (Date.now() - new Date(logDate + 'T12:00:00').getTime()) / 864e5;
3057
+ if (logAgeDays > 7) continue;
3058
+ }
3049
3059
  const text = safeReadText(filePath);
3050
3060
  if (!text) continue;
3051
3061
  filesScanned += 1;
@@ -3419,7 +3429,7 @@ function collectAutoImproverScan(root = process.cwd()) {
3419
3429
  }
3420
3430
 
3421
3431
  // Lifecycle filter for wake dedupe: a task that already crossed the review boundary
3422
- // (done/failed/archived, or human-accepted) must never be re-selected as the wake target
3432
+ // (done/failed/archived, or human-accepted) must never be re-selected as the wake target,
3423
3433
  // that loop produced an endless "existing_task_found OBL-1433" no-op spiral (OBL-1469).
3424
3434
  const AUTO_IMPROVER_INACTIVE_STATUSES = new Set(['done', 'failed', 'archived']);
3425
3435
 
@@ -3604,7 +3614,7 @@ async function runAutoImproverWake(name, paths, { execute = false, confirmed = f
3604
3614
  };
3605
3615
  const previousLatest = readJson(path.join(process.cwd(), '.atris', 'state', 'auto-improver-dogfood-latest.json'));
3606
3616
  const finalWrite = writeAutoImproverReceipt(name, payload, plannedReceiptPath);
3607
- // A no-op scan identical to the previous tick earns a receipt but not a journal entry
3617
+ // A no-op scan identical to the previous tick earns a receipt but not a journal entry,
3608
3618
  // the cadence loop was appending the same "found: N, prevented: 0" row every ~4 minutes
3609
3619
  // and flooding the daily log (2026-06-10 had 100+ identical entries).
3610
3620
  const createdNewTask = Boolean(payload.created_task) && payload.created_task.existing === false;
@@ -3801,7 +3811,7 @@ function appendProjectLog(title, fields = {}) {
3801
3811
  function parseFrontmatter(content) {
3802
3812
  // \r?\n so a CRLF-line-ending MEMBER.md (Windows-edited) still parses; otherwise
3803
3813
  // the delimiter never matched (and trailing \r broke the per-line key matchers),
3804
- // silently dropping the member's entire frontmatter role, skills, permissions, tools.
3814
+ // silently dropping the member's entire frontmatter: role, skills, permissions, tools.
3805
3815
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
3806
3816
  if (!match) return null;
3807
3817
 
@@ -4047,14 +4057,6 @@ async function memberCreate(name, ...flags) {
4047
4057
  process.exit(1);
4048
4058
  }
4049
4059
 
4050
- // Scaffold
4051
- fs.mkdirSync(memberDir, { recursive: true });
4052
- fs.mkdirSync(path.join(memberDir, 'skills'), { recursive: true });
4053
- fs.mkdirSync(path.join(memberDir, 'tools'), { recursive: true });
4054
- fs.mkdirSync(path.join(memberDir, 'context'), { recursive: true });
4055
- const logPath = ensureMemberLog(memberDir, { name, role, description: description || `Handles ${role.toLowerCase()} tasks` });
4056
- ensureMissionFile(memberDir, { name, role, description: description || `Handles ${role.toLowerCase()} tasks` });
4057
-
4058
4060
  const content = `---
4059
4061
  name: ${name}
4060
4062
  role: ${role}
@@ -4114,11 +4116,20 @@ tools: []
4114
4116
  2. Rule two
4115
4117
  `;
4116
4118
 
4117
- fs.writeFileSync(memberFile, content);
4119
+ const memberDescription = description || `Handles ${role.toLowerCase()} tasks`;
4120
+ const { logPath } = ensureMemberBundle(memberDir, {
4121
+ name,
4122
+ role,
4123
+ description: memberDescription,
4124
+ source: 'cli',
4125
+ memberContent: content,
4126
+ });
4118
4127
 
4119
4128
  console.log('');
4120
4129
  console.log(`✓ Created team/${name}/MEMBER.md`);
4130
+ console.log(`✓ Created team/${name}/SOUL.md`);
4121
4131
  console.log(`✓ Created team/${name}/MISSION.md`);
4132
+ console.log(`✓ Created team/${name}/goals.json + goals.md`);
4122
4133
  console.log(`✓ Created team/${name}/skills/`);
4123
4134
  console.log(`✓ Created team/${name}/tools/`);
4124
4135
  console.log(`✓ Created team/${name}/context/`);
@@ -4317,17 +4328,18 @@ function memberUpgrade(name) {
4317
4328
  process.exit(1);
4318
4329
  }
4319
4330
 
4320
- // Move flat file to directory format
4331
+ // Move flat file to directory format, then backfill the complete identity bundle.
4321
4332
  fs.mkdirSync(memberDir, { recursive: true });
4322
- fs.mkdirSync(path.join(memberDir, 'skills'), { recursive: true });
4323
- fs.mkdirSync(path.join(memberDir, 'tools'), { recursive: true });
4324
- fs.mkdirSync(path.join(memberDir, 'context'), { recursive: true });
4325
- const logPath = ensureMemberLog(memberDir, { name, source: 'upgrade' });
4326
4333
  fs.renameSync(legacyFile, memberFile);
4327
- ensureMissionFile(memberDir, { name, description: 'Define why this member exists and how it chooses goals.' });
4334
+ const { logPath } = ensureMemberBundle(memberDir, {
4335
+ name,
4336
+ role: name,
4337
+ description: 'Define why this member exists and how it chooses goals.',
4338
+ source: 'upgrade',
4339
+ });
4328
4340
 
4329
4341
  console.log(`✓ Upgraded team/${name}.md → team/${name}/MEMBER.md`);
4330
- console.log(`✓ Created MISSION.md, skills/, tools/, context/, logs/${path.basename(logPath)}`);
4342
+ console.log(`✓ Created SOUL.md, MISSION.md, goals.json, goals.md, skills/, tools/, context/, logs/${path.basename(logPath)}`);
4331
4343
  }
4332
4344
 
4333
4345
  // --- PUSH subcommand ---
@@ -4695,7 +4707,7 @@ function memberGoalFromMission(name, ...args) {
4695
4707
  );
4696
4708
  return;
4697
4709
  }
4698
- // The title IS the mission focus no boilerplate prefix; the acceptance list already
4710
+ // The title IS the mission focus, no boilerplate prefix; the acceptance list already
4699
4711
  // says "one bounded step" and the why carries the full sentence.
4700
4712
  const title = compactSentence(runtimeFocus, 96);
4701
4713
  const existing = state.goals.find((goal) => (
@@ -4753,7 +4765,7 @@ function memberGoalFromMission(name, ...args) {
4753
4765
  mission_status: runtime.status || null,
4754
4766
  };
4755
4767
  // Collapse repeated no-op reuse ticks (same mission state) instead of recording an identical entry
4756
- // every cadence that grew one member's goals.json to 2,200+ duplicate entries / 13K lines. Real
4768
+ // every cadence, that grew one member's goals.json to 2,200+ duplicate entries / 13K lines. Real
4757
4769
  // transitions (created, changed mission id/status) are still kept; only consecutive dupes are dropped.
4758
4770
  const lastEntry = goal.history[goal.history.length - 1];
4759
4771
  const isDuplicateReuse = existing && lastEntry
@@ -4935,7 +4947,7 @@ function fallbackProposalForGoal(goal, context = {}) {
4935
4947
  const drill = scoreEvidence?.drill || null;
4936
4948
  const fileEvidence = context?.evidence?.goal_files || context?.goal_files || null;
4937
4949
  const primaryFile = (fileEvidence?.files || []).find((file) => file.exists && file.excerpt) || null;
4938
- // Don't restate the goal title inside the experiment the experiment lives under the goal.
4950
+ // Don't restate the goal title inside the experiment, the experiment lives under the goal.
4939
4951
  const title = drill && target
4940
4952
  ? `Run ${target.label || target.slug} drill: ${compactSentence(drill, 96)}`
4941
4953
  : drill
@@ -5170,6 +5182,13 @@ Wiki content:
5170
5182
  ${pageContent}`;
5171
5183
  }
5172
5184
 
5185
+ function isWikiMinerNoiseName(value) {
5186
+ const name = compactSentence(value || '', 120);
5187
+ if (!name) return true;
5188
+ if (/^[A-Z]{2,}$/.test(name)) return false;
5189
+ return /^(?:i|me|my|mine|myself|we|us|our|ours|ourselves|you|your|yours|yourself|yourselves|he|him|his|himself|she|her|hers|herself|it|its|itself|they|them|their|theirs|themselves|this|that|these|those|the|wiki|mission)$/i.test(name);
5190
+ }
5191
+
5173
5192
  function normalizeWikiMinerExtraction(raw) {
5174
5193
  if (!raw || typeof raw !== 'object') return null;
5175
5194
  const allowedEntityTypes = new Set(['person', 'system', 'concept']);
@@ -5179,14 +5198,14 @@ function normalizeWikiMinerExtraction(raw) {
5179
5198
  type: allowedEntityTypes.has(String(entity?.type || '').toLowerCase()) ? String(entity.type).toLowerCase() : 'concept',
5180
5199
  name: compactSentence(entity?.name || '', 120),
5181
5200
  }))
5182
- .filter((entity) => entity.name);
5201
+ .filter((entity) => !isWikiMinerNoiseName(entity.name));
5183
5202
  const relationships = (Array.isArray(raw.relationships) ? raw.relationships : [])
5184
5203
  .map((relationship) => ({
5185
5204
  from: compactSentence(relationship?.from || '', 120),
5186
5205
  to: compactSentence(relationship?.to || '', 120),
5187
5206
  type: allowedRelationTypes.has(String(relationship?.type || '').toLowerCase()) ? String(relationship.type).toLowerCase() : 'uses',
5188
5207
  }))
5189
- .filter((relationship) => relationship.from && relationship.to);
5208
+ .filter((relationship) => !isWikiMinerNoiseName(relationship.from) && !isWikiMinerNoiseName(relationship.to));
5190
5209
  return { entities, relationships };
5191
5210
  }
5192
5211
 
@@ -5202,7 +5221,7 @@ function heuristicWikiMinerExtraction(pagePath, pageContent) {
5202
5221
  let match = pattern.exec(pageContent);
5203
5222
  while (match) {
5204
5223
  const value = compactSentence(match[1] || match[0], 80);
5205
- if (value && !/^the|this|that|wiki|mission$/i.test(value)) candidates.add(value);
5224
+ if (!isWikiMinerNoiseName(value)) candidates.add(value);
5206
5225
  match = pattern.exec(pageContent);
5207
5226
  }
5208
5227
  }
@@ -5249,6 +5268,7 @@ async function callWikiMinerLlm(pagePath, pageContent, pageIndex) {
5249
5268
  function mergeWikiGraph(graph, extraction, sourcePath) {
5250
5269
  const entityMap = new Map();
5251
5270
  for (const entity of graph.entities || []) {
5271
+ if (isWikiMinerNoiseName(entity.name)) continue;
5252
5272
  const key = `${String(entity.type || 'concept').toLowerCase()}:${lowerCompact(entity.name)}`;
5253
5273
  entityMap.set(key, { ...entity, sources: Array.isArray(entity.sources) ? entity.sources : [] });
5254
5274
  }
@@ -5261,6 +5281,7 @@ function mergeWikiGraph(graph, extraction, sourcePath) {
5261
5281
 
5262
5282
  const relationshipMap = new Map();
5263
5283
  for (const relationship of graph.relationships || []) {
5284
+ if (isWikiMinerNoiseName(relationship.from) || isWikiMinerNoiseName(relationship.to)) continue;
5264
5285
  const key = `${lowerCompact(relationship.from)}|${String(relationship.type || 'uses').toLowerCase()}|${lowerCompact(relationship.to)}`;
5265
5286
  relationshipMap.set(key, { ...relationship, sources: Array.isArray(relationship.sources) ? relationship.sources : [] });
5266
5287
  }
@@ -7250,13 +7271,13 @@ function readMemberScope(name, paths) {
7250
7271
  if (typeof p === 'string' && p.trim()) scope.push(p.trim());
7251
7272
  }
7252
7273
  }
7253
- } catch { /* ignore fall through with default scope */ }
7274
+ } catch { /* ignore, fall through with default scope */ }
7254
7275
  }
7255
7276
  return scope;
7256
7277
  }
7257
7278
 
7258
7279
  // Auto-generated artifacts that wake/tick produce as side-effects. Dirty here is expected
7259
- // and must not gate the next wake otherwise the loop deadlocks on its own log writes.
7280
+ // and must not gate the next wake, otherwise the loop deadlocks on its own log writes.
7260
7281
  function isAutoGeneratedArtifact(filePath, name) {
7261
7282
  const memberLogs = `atris/team/${name}/logs/`;
7262
7283
  if (filePath.startsWith(memberLogs)) return true;
@@ -7421,7 +7442,7 @@ function wakeRuleAutonomousErrorTask(ctx) {
7421
7442
  };
7422
7443
  }
7423
7444
 
7424
- // Rule: no active goal adopt a discovered problem as the objective, else stop.
7445
+ // Rule: no active goal, adopt a discovered problem as the objective, else stop.
7425
7446
  function wakeRuleNeedsGoal(ctx) {
7426
7447
  if (ctx.goal) return null;
7427
7448
  const discoveredProblem = ctx.evidence.problem_discovery?.selected || null;
@@ -7495,7 +7516,7 @@ function wakeRuleDirtyMemberScope(ctx) {
7495
7516
  return {
7496
7517
  decision: 'wait',
7497
7518
  reason: 'workspace_dirty_in_member_scope',
7498
- next_command: `commit/stash files in atris/team/${ctx.name}/ (or member scope) or rerun: atris member wake ${ctx.name} --force`,
7519
+ next_command: `commit/stash files in atris/team/${ctx.name}/ (or member scope), or rerun: atris member wake ${ctx.name} --force`,
7499
7520
  goal: ctx.goal,
7500
7521
  current_experiment: null,
7501
7522
  };
@@ -7784,7 +7805,7 @@ const WAKE_REASON_TEXT = {
7784
7805
  mission_missing_or_placeholder: "it has no North Star yet, and it won't guess at important work",
7785
7806
  no_active_goal: 'it has no active goal to push on yet',
7786
7807
  execute_requires_confirm_autonomy_policy: 'autonomous execution waits for your explicit go-ahead',
7787
- workspace_dirty_in_member_scope: "there are uncommitted changes in its own lane it won't build on a dirty floor",
7808
+ workspace_dirty_in_member_scope: "there are uncommitted changes in its own lane, it won't build on a dirty floor",
7788
7809
  blocked_experiment: 'its current experiment is blocked on a human answer',
7789
7810
  tick_executed_experiment_proposed: 'it proposed one bounded experiment and queued it for your review',
7790
7811
  safe_next_bounded_step: 'it found a safe bounded next step',
@@ -8184,6 +8205,7 @@ function memberLoopAliveTick(name, run, index, tickStartedAt) {
8184
8205
  maxWallSeconds: options.operateMaxWall,
8185
8206
  autoAcceptLimit: options.autoAcceptLimit,
8186
8207
  noPrime: index > 0,
8208
+ sharedCheckout: options.sharedCheckout,
8187
8209
  });
8188
8210
  const key = `${alive.status || 'alive'}:${alive.reason || 'tick'}`;
8189
8211
  state.decisions[key] = (state.decisions[key] || 0) + 1;
@@ -8194,7 +8216,7 @@ function memberLoopAliveTick(name, run, index, tickStartedAt) {
8194
8216
  ok: alive.ok !== false,
8195
8217
  decision: alive.status || 'alive_tick',
8196
8218
  reason: alive.reason || null,
8197
- executed: options.execute,
8219
+ executed: options.execute && alive.operate?.payload?.executed !== false,
8198
8220
  needs_user: alive.needs_user === true,
8199
8221
  next_command: alive.next_command || null,
8200
8222
  has_mission: alive.has_mission === true,
@@ -8208,6 +8230,7 @@ function memberLoopAliveTick(name, run, index, tickStartedAt) {
8208
8230
  alive,
8209
8231
  };
8210
8232
  state.tickResults.push(tick);
8233
+ if (!tick.ok) state.failed = true;
8211
8234
  fs.appendFileSync(state.tickLogPath, JSON.stringify(tick) + '\n', 'utf8');
8212
8235
  }
8213
8236
 
@@ -8340,13 +8363,14 @@ function memberLoopRecordResult(name, paths, lease, run) {
8340
8363
  const { hourly, forever, runId, ticks, intervalMs, durationMs, startedAt } = plan;
8341
8364
  const { tickResults, decisions, stopped, failed, earlyExit, tickLogPath } = state;
8342
8365
  const finishedAt = stampIso();
8366
+ const plannedOnly = aliveMode && tickResults.length > 0 && tickResults.every((tick) => tick.decision === 'planned');
8343
8367
  const summary = {
8344
8368
  ok: !failed,
8345
8369
  action: aliveMode ? 'alive' : 'loop',
8346
8370
  schema: aliveMode ? 'atris.member_alive.v1' : 'atris.member_loop.v1',
8347
8371
  member: name,
8348
8372
  alive: aliveMode,
8349
- status: failed ? 'failed' : stopped ? 'stopped' : earlyExit ? (earlyExit.blocked_on_human ? 'blocked_on_human' : 'idle') : 'completed',
8373
+ status: failed ? 'failed' : stopped ? 'stopped' : plannedOnly ? 'planned' : earlyExit ? (earlyExit.blocked_on_human ? 'blocked_on_human' : 'idle') : 'completed',
8350
8374
  mode: execute ? 'execute' : 'dry_run',
8351
8375
  cadence: hourly ? 'hourly' : 'custom',
8352
8376
  forever,
@@ -8406,7 +8430,8 @@ async function memberLoop(name, ...args) {
8406
8430
  const model = String(readFlag(args, '--model', '') || '').trim() || undefined;
8407
8431
  const operateMaxWall = Math.max(60, Math.min(1800, Number(readNumberFlag(args, '--operate-max-wall', readNumberFlag(args, '--max-wall', 900)))));
8408
8432
  const autoAcceptLimit = Math.max(1, Math.floor(Number(readNumberFlag(args, '--auto-accept-limit', 8))));
8409
- const options = { asJson, aliveMode, execute, confirmed, force, agent, model, operateMaxWall, autoAcceptLimit };
8433
+ const sharedCheckout = hasFlag(args, '--shared-checkout');
8434
+ const options = { asJson, aliveMode, execute, confirmed, force, agent, model, operateMaxWall, autoAcceptLimit, sharedCheckout };
8410
8435
  const paths = memberLoopPaths(name);
8411
8436
  fs.mkdirSync(paths.stateDir, { recursive: true });
8412
8437
 
@@ -8932,7 +8957,7 @@ function memberScopeQuery(flags) {
8932
8957
  return q;
8933
8958
  }
8934
8959
 
8935
- // atris member live what the iPhone app and web see: GET /api/members projection.
8960
+ // atris member live, what the iPhone app and web see: GET /api/members projection.
8936
8961
  async function memberLive(...args) {
8937
8962
  const { flags } = parseLiveFlags(args);
8938
8963
  const creds = loadCredentials();
@@ -8951,7 +8976,7 @@ async function memberLive(...args) {
8951
8976
  return;
8952
8977
  }
8953
8978
  console.log('');
8954
- console.log(`live members (${flags.scope}${flags.scopeId ? `:${flags.scopeId}` : ''}) same projection the app renders`);
8979
+ console.log(`live members (${flags.scope}${flags.scopeId ? `:${flags.scopeId}` : ''}), same projection the app renders`);
8955
8980
  console.log('');
8956
8981
  for (const m of members) {
8957
8982
  const loop = m.loop_status || {};
@@ -8965,7 +8990,7 @@ async function memberLive(...args) {
8965
8990
  console.log('');
8966
8991
  }
8967
8992
 
8968
- // atris member heartbeat tell the backend this member is running/done, so
8993
+ // atris member heartbeat, tell the backend this member is running/done, so
8969
8994
  // every surface (iOS, web) shows it live. POST /api/members/{name}/heartbeat.
8970
8995
  async function memberHeartbeat(name, ...args) {
8971
8996
  if (!name) {
@@ -8996,10 +9021,10 @@ async function memberHeartbeat(name, ...args) {
8996
9021
  return;
8997
9022
  }
8998
9023
  const d = result.data || {};
8999
- console.log(`${d.running ? '●' : '○'} ${d.member || name} → ${d.state}${d.working_on ? ` ${d.working_on}` : ''} (visible on every surface)`);
9024
+ console.log(`${d.running ? '●' : '○'} ${d.member || name} → ${d.state}${d.working_on ? `, ${d.working_on}` : ''} (visible on every surface)`);
9000
9025
  }
9001
9026
 
9002
- // atris member improvements what the business computer improved, day by day.
9027
+ // atris member improvements, what the business computer improved, day by day.
9003
9028
  // GET /api/business/{id}/improvements/daily.
9004
9029
  async function memberImprovements(businessId, ...args) {
9005
9030
  if (!businessId) {
@@ -9024,15 +9049,15 @@ async function memberImprovements(businessId, ...args) {
9024
9049
  }
9025
9050
  const history = result.data?.history || [];
9026
9051
  console.log('');
9027
- console.log(`daily improvements business ${businessId}`);
9052
+ console.log(`daily improvements: business ${businessId}`);
9028
9053
  console.log('');
9029
9054
  if (history.length === 0) {
9030
- console.log(' (no improvement history yet first entry lands after the next nightly self-improve run)');
9055
+ console.log(' (no improvement history yet, first entry lands after the next nightly self-improve run)');
9031
9056
  }
9032
9057
  for (const day of history) {
9033
9058
  console.log(` ${day.date}: ${day.agents_improved}/${day.agents_total} agents improved`);
9034
9059
  for (const agent of day.agents || []) {
9035
- const note = agent.note ? ` ${agent.note}` : '';
9060
+ const note = agent.note ? `, ${agent.note}` : '';
9036
9061
  console.log(` ${agent.kept_count > 0 ? '+' : ' '} ${agent.name} (kept ${agent.kept_count}, score ${agent.best_score})${note}`);
9037
9062
  }
9038
9063
  }
@@ -9063,7 +9088,7 @@ async function memberChat(name, ...rest) {
9063
9088
  async function memberCommand(subcommand, ...args) {
9064
9089
  // Subcommands that take a member name as args[0] otherwise treat `--help` as
9065
9090
  // a name and error with "Member '--help' not found". `create`/`new` handle
9066
- // help themselves (with subcommand-specific usage) leave those alone.
9091
+ // help themselves (with subcommand-specific usage), leave those alone.
9067
9092
  const HELP_AWARE_SUBCOMMANDS = new Set(['create', 'new', 'run', 'install']);
9068
9093
  if (!HELP_AWARE_SUBCOMMANDS.has(subcommand) && (args[0] === '-h' || args[0] === '--help')) {
9069
9094
  subcommand = undefined;