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
@@ -84,7 +84,7 @@ Direct. No filler. Every sentence either presents evidence or connects evidence
84
84
 
85
85
  When you complete research:
86
86
  1. Deliver the brief to whoever asked
87
- 2. Log to your journal at `atris/team/researcher/journal/YYYY-MM-DD.md`:
87
+ 2. Log at `atris/team/researcher/logs/YYYY-MM-DD.md`:
88
88
 
89
89
  ```markdown
90
90
  ## Researcher - Mon DD
@@ -95,4 +95,4 @@ When you complete research:
95
95
  **Learned:** What surprised you or what the team should know
96
96
  ```
97
97
 
98
- Your journal helps the next research session avoid re-treading old ground.
98
+ Your log helps the next research session avoid re-treading old ground.
@@ -243,7 +243,7 @@ After validation:
243
243
  2. Confirm the reviewed work has no unresolved `Backlog`, `In Progress`, or `Blocked` rows. Completed rows are durable history.
244
244
  3. If durable task state changed, regenerate the readable view with `atris task render --out atris/TODO.md`; do not hand-delete rendered completed history.
245
245
  4. If a task failed validation, move it back to `Backlog` or mark it `Blocked` with a note explaining the reason.
246
- 5. Log to your journal at `atris/team/validator/journal/YYYY-MM-DD.md`:
246
+ 5. Log at `atris/team/validator/logs/YYYY-MM-DD.md`:
247
247
 
248
248
  ```markdown
249
249
  ## Validator - Mon DD
package/atris.md CHANGED
@@ -37,6 +37,20 @@ straight to the work):
37
37
 
38
38
  If a task was already given, show the box and proceed with that task.
39
39
 
40
+ ## concierge
41
+
42
+ The person you work for does not know atris words and never has to learn them. Never tell them to run an atris command or learn a term.
43
+
44
+ When their words match a supported move, run it and report what happened in plain words. When unsure, run `atris guide "<their words>"` and follow its answer. Run `atris guide` for the current list.
45
+
46
+ After anything lands, offer one next move in plain words, never a command name.
47
+
48
+ Moves marked asks you first send messages, spend credits, or run for hours. Say in one sentence what would happen and wait for a yes before running them. Never add a skip flag like --yes on the person's behalf.
49
+
50
+ Never end a reply with a command for the person to run. If a move needs a claim or an approval, do it for them and say what you did.
51
+
52
+ In a project with nothing on the list yet, speak first: three things you noticed about the codebase, one question, then start on the most useful one.
53
+
40
54
  ## operating rules
41
55
 
42
56
  You can move fast. You do not get to move blindly.
package/ax CHANGED
@@ -78,7 +78,7 @@ const ANSI = {
78
78
  magenta: '\x1b[35m'
79
79
  };
80
80
 
81
- const TIER_COLORS = { rapid: '\x1b[33m', fast: '\x1b[32m', pro: '\x1b[36m', max: '\x1b[35m' };
81
+ const TIER_COLORS = { alpha: '\x1b[93m', rapid: '\x1b[33m', fast: '\x1b[32m', pro: '\x1b[36m', max: '\x1b[35m' };
82
82
 
83
83
  // Extend backend_api by adding one row here. Keep mutating endpoints narrow;
84
84
  // any non-get method is approval-gated before the HTTP request is made.
@@ -99,6 +99,7 @@ function tierColor(mode) {
99
99
  function modelForMode(mode) {
100
100
  if (mode === 'code-fast') return CODE_FAST.model;
101
101
  if (mode === 'max') return 'atris:max';
102
+ if (mode === 'alpha') return 'atris:alpha';
102
103
  if (mode === 'rapid') return 'atris:rapid';
103
104
  return mode === 'fast' ? 'atris:fast' : 'atris:pro';
104
105
  }
@@ -121,7 +122,7 @@ function postTurnTimeoutMs(payload = {}, options = {}) {
121
122
  // AX postTurn is the tool-capable Atris2 path. Fast tool turns need the same
122
123
  // headroom as pro because the backend can spend long stretches inside tools
123
124
  // without SSE traffic. Plain tool-free one-shot fast chat stays at 60s.
124
- if ((model === 'atris:fast' || model === 'atris:rapid') && payloadCanRunTools(payload, options)) {
125
+ if ((model === 'atris:fast' || model === 'atris:rapid' || model === 'atris:alpha') && payloadCanRunTools(payload, options)) {
125
126
  timeoutMs = Math.max(timeoutMs, PRO_TURN_TIMEOUT_MS);
126
127
  }
127
128
  if (options.business || options.local) {
@@ -147,16 +148,18 @@ function formatSeconds(totalSeconds) {
147
148
  function tierLabel(mode) {
148
149
  if (mode === 'code-fast') return 'Atris Code Fast';
149
150
  if (mode === 'max') return 'Atris 2 Max';
151
+ if (mode === 'alpha') return 'Atris Alpha';
150
152
  if (mode === 'rapid') return 'Atris Rapid';
151
153
  if (mode === 'fast') return 'Atris 2 Fast';
152
154
  return 'Atris 2 Pro';
153
155
  }
154
156
 
155
- function formatHeader({ mode = 'pro', cwd = process.cwd(), chat = false } = {}, options = {}) {
157
+ function formatHeader({ mode = 'pro', cwd = process.cwd(), chat = false, reasoningEffort = null } = {}, options = {}) {
158
+ const effortSuffix = reasoningEffort ? ` · effort ${reasoningEffort}` : '';
156
159
  return [
157
- paint(`${tierLabel(mode)}${chat ? ' chat' : ''}`, [ANSI.bold, tierColor(normalizeMode(mode))], options),
160
+ paint(`${tierLabel(mode)}${chat ? ' chat' : ''}${effortSuffix}`, [ANSI.bold, tierColor(normalizeMode(mode))], options),
158
161
  cwd,
159
- chat ? paint('shift-tab bypass · /auto /log /today /now /who · /fast /pro /max /rapid · exit to leave', [ANSI.muted], options) : '',
162
+ chat ? paint('shift-tab bypass · /auto /log /today /now /who · /fast /pro /max /rapid /alpha /effort · exit to leave', [ANSI.muted], options) : '',
160
163
  ].filter(Boolean).join('\n');
161
164
  }
162
165
 
@@ -165,11 +168,11 @@ function formatUsage() {
165
168
  'ax - Atris local/code agent',
166
169
  '',
167
170
  'Usage:',
168
- ' ax [--auto|--max|--pro|--fast|--rapid|--code-fast] [--local|--cloud] <message>',
169
- ' ax [--auto|--max|--pro|--fast|--rapid|--code-fast] [--local|--cloud] --print <message>',
170
- ' ax [--auto|--max|--pro|--fast|--rapid|--code-fast] [--local|--cloud] --chat',
171
- ' ax [--max|--pro|--fast|--rapid] --business <slug> [<message>|--chat]',
172
- ' ax [--max|--pro|--fast|--rapid|--code-fast] --doctor',
171
+ ' ax [--auto|--max|--pro|--fast|--rapid|--alpha|--code-fast] [--local|--cloud] <message>',
172
+ ' ax [--auto|--max|--pro|--fast|--rapid|--alpha|--code-fast] [--local|--cloud] --print <message>',
173
+ ' ax [--auto|--max|--pro|--fast|--rapid|--alpha|--code-fast] [--local|--cloud] --chat',
174
+ ' ax [--max|--pro|--fast|--rapid|--alpha] --business <slug> [<message>|--chat]',
175
+ ' ax [--max|--pro|--fast|--rapid|--alpha|--code-fast] --doctor',
173
176
  ' ax --approvals',
174
177
  ' ax --approve <approval-id>',
175
178
  ' ax --deny <approval-id>',
@@ -187,6 +190,8 @@ function formatUsage() {
187
190
  ' --pro hosted Atris 2, deeper tool loop',
188
191
  ' --fast hosted Atris 2, faster low-latency turns',
189
192
  ' --rapid hosted Atris Rapid, cheapest chat and first-hop tools',
193
+ ' --alpha hosted experimental lane (free preview model, swap via ATRIS2_ALPHA_MODEL)',
194
+ ' --effort <level> reasoning effort: none, low, medium, high, xhigh, or default',
190
195
  ' --code-fast Atris Code Fast public lane',
191
196
  ' --local opt into local backend/workspace tools',
192
197
  ' --cloud force authenticated cloud connectors/chat',
@@ -198,6 +203,7 @@ function formatUsage() {
198
203
  ' ax --pro find the config file and explain it',
199
204
  ' ax --fast what files are here',
200
205
  ' ax --rapid --chat',
206
+ ' ax --alpha --chat',
201
207
  ' ax --max refactor this module and verify the tests',
202
208
  ' ax --max --verify "npm test" fix the failing suite',
203
209
  ' ax --code-fast explain this error',
@@ -943,9 +949,20 @@ function insideWorkspaceCwd(startDir) {
943
949
  return found;
944
950
  }
945
951
 
952
+ function pinLocalCheckout(options = {}) {
953
+ if (options.forceCloud || options.route === 'cloud') return false;
954
+ return Boolean(
955
+ options.forceLocal
956
+ || options.route === 'local'
957
+ || options.mode === 'alpha'
958
+ );
959
+ }
960
+
946
961
  function resolveRoute(message, options = {}) {
947
962
  if (options.route === 'local' || options.forceLocal) return 'local';
948
963
  if (options.route === 'cloud' || options.forceCloud) return 'cloud';
964
+ // Alpha is the coding CLI: stay on this checkout. Never silent-cloud.
965
+ if (options.mode === 'alpha') return 'local';
949
966
  // Workspace standard v2 (2026-07-02, supersedes intent routing): inside a
950
967
  // workspace, tools are ALWAYS attached and the model decides whether to use
951
968
  // them — the Claude Code / Codex shape. v1 guessed intent with regexes and
@@ -970,6 +987,7 @@ function resolveRoute(message, options = {}) {
970
987
  function normalizeMode(mode) {
971
988
  if (mode === 'code-fast' || mode === 'code') return 'code-fast';
972
989
  if (mode === 'max') return 'max';
990
+ if (mode === 'alpha') return 'alpha';
973
991
  if (mode === 'rapid') return 'rapid';
974
992
  return mode === 'fast' ? 'fast' : 'pro';
975
993
  }
@@ -1127,8 +1145,25 @@ const TIER_BLURBS = {
1127
1145
  fast: 'quick answers, lowest latency',
1128
1146
  pro: 'deeper tool loop for real work',
1129
1147
  max: 'highest reasoning for the hardest jobs',
1148
+ alpha: 'experimental preview lane',
1130
1149
  };
1131
1150
 
1151
+ const REASONING_EFFORTS = Object.freeze(['none', 'low', 'medium', 'high', 'xhigh']);
1152
+
1153
+ function normalizeReasoningEffort(value) {
1154
+ const raw = String(value || '').trim().toLowerCase();
1155
+ if (!raw || raw === 'default' || raw === 'auto') return null;
1156
+ const num = Number(raw);
1157
+ if (Number.isInteger(num) && num >= 1 && num <= REASONING_EFFORTS.length) {
1158
+ return REASONING_EFFORTS[num - 1];
1159
+ }
1160
+ return REASONING_EFFORTS.includes(raw) ? raw : '';
1161
+ }
1162
+
1163
+ function formatReasoningEffortLabel(value) {
1164
+ return value ? String(value) : 'lane default';
1165
+ }
1166
+
1132
1167
  const CHAT_COMMANDS = Object.freeze([
1133
1168
  { name: '/help', description: 'list all commands', type: 'help' },
1134
1169
  { name: '/model', description: 'show the current lane and how to switch', type: 'model' },
@@ -1137,6 +1172,8 @@ const CHAT_COMMANDS = Object.freeze([
1137
1172
  { name: '/pro', description: 'switch to a deeper tool loop', type: 'tier', mode: 'pro' },
1138
1173
  { name: '/max', description: 'switch to the highest reasoning lane', type: 'tier', mode: 'max' },
1139
1174
  { name: '/rapid', description: 'switch to the cheapest chat lane', type: 'tier', mode: 'rapid' },
1175
+ { name: '/alpha', description: 'switch to the experimental preview lane', type: 'tier', mode: 'alpha' },
1176
+ { name: '/effort', description: 'set reasoning effort (none → xhigh)', type: 'effort' },
1140
1177
  { name: '/new', description: 'start a new conversation', type: 'clear' },
1141
1178
  { name: '/clear', description: 'reset the current conversation', type: 'clear' },
1142
1179
  { name: '/context', description: 'show the conversation size', type: 'context' },
@@ -1263,14 +1300,44 @@ function runChatSlash(line, options = {}) {
1263
1300
  if (command.type === 'model') {
1264
1301
  return {
1265
1302
  type: 'model',
1266
- output: `· current lane: ${tierLabel(mode)} · switch with /fast /pro /max /rapid`,
1303
+ output: `· current lane: ${tierLabel(mode)} · effort: ${formatReasoningEffortLabel(options.reasoningEffort)} · switch with /fast /pro /max /rapid /alpha · effort with /effort`,
1304
+ };
1305
+ }
1306
+ if (command.type === 'effort') {
1307
+ const current = formatReasoningEffortLabel(options.reasoningEffort);
1308
+ if (parsed.arg) {
1309
+ if (parsed.arg.toLowerCase() === 'default') {
1310
+ return { type: 'effort', reasoningEffort: null, output: '· effort: lane default' };
1311
+ }
1312
+ const next = normalizeReasoningEffort(parsed.arg);
1313
+ if (!next) {
1314
+ return {
1315
+ type: 'effort',
1316
+ output: [
1317
+ '· usage: /effort none|low|medium|high|xhigh|default',
1318
+ ...REASONING_EFFORTS.map((level, index) => ` ${index + 1} ${level}`),
1319
+ ].join('\n'),
1320
+ };
1321
+ }
1322
+ return { type: 'effort', reasoningEffort: next, output: `· effort: ${next}` };
1323
+ }
1324
+ return {
1325
+ type: 'effort',
1326
+ output: [
1327
+ `· effort: ${current}`,
1328
+ ' pick: /effort none | low | medium | high | xhigh | default',
1329
+ ...REASONING_EFFORTS.map((level, index) => ` ${index + 1} ${level}`),
1330
+ ].join('\n'),
1267
1331
  };
1268
1332
  }
1269
1333
  if (command.type === 'status') {
1270
1334
  return { type: 'status', output: '' };
1271
1335
  }
1272
1336
  if (command.type === 'who') {
1273
- return { type: 'who', output: `· ${tierLabel(mode)} · ${TIER_BLURBS[mode] || 'chat'}` };
1337
+ return {
1338
+ type: 'who',
1339
+ output: `· ${tierLabel(mode)} · effort ${formatReasoningEffortLabel(options.reasoningEffort)} · ${TIER_BLURBS[mode] || 'chat'}`,
1340
+ };
1274
1341
  }
1275
1342
  if (command.type === 'auto') {
1276
1343
  const next = nextApproveMode(parsed.arg, options.approveMode);
@@ -2968,6 +3035,9 @@ function buildPayload(message, options = {}) {
2968
3035
  if (turnId) {
2969
3036
  payload.turn_id = turnId;
2970
3037
  }
3038
+ if (options.reasoningEffort) {
3039
+ payload.reasoning_effort = String(options.reasoningEffort);
3040
+ }
2971
3041
  const connectorPolicy = !local ? connectorTurnPolicy(message, { ...options, turnId }) : null;
2972
3042
  if (connectorPolicy) {
2973
3043
  payload.connector_turn = connectorPolicy;
@@ -3164,7 +3234,7 @@ function isTurnInterruptedError(error) {
3164
3234
 
3165
3235
  async function postTurn(message, options = {}) {
3166
3236
  let route = options.business ? 'local' : resolveRoute(message, options);
3167
- if (route === 'local' && !options.business && options.route !== 'local' && !options.forceLocal
3237
+ if (route === 'local' && !options.business && !pinLocalCheckout(options)
3168
3238
  && !(await localBackendReachable())) {
3169
3239
  route = 'cloud';
3170
3240
  }
@@ -3492,6 +3562,7 @@ async function runHeadlessTurn(message, options = {}) {
3492
3562
  route: options.route,
3493
3563
  business: options.business,
3494
3564
  verify: options.verify,
3565
+ reasoningEffort: options.reasoningEffort,
3495
3566
  output: sink,
3496
3567
  showProgress: false,
3497
3568
  });
@@ -3528,13 +3599,16 @@ async function chat(options = {}) {
3528
3599
  const history = [];
3529
3600
  let lastCompactionNotice = 0;
3530
3601
  let conversationId = options.conversationId || `ax-${process.pid}-${Date.now().toString(36)}`;
3531
- const session = { approveMode: options.autoApprove || options.approveMode === 'auto' ? 'auto' : 'stage' };
3602
+ const session = {
3603
+ approveMode: options.autoApprove || options.approveMode === 'auto' ? 'auto' : 'stage',
3604
+ reasoningEffort: options.reasoningEffort || null,
3605
+ };
3532
3606
  let turnInFlight = false;
3533
3607
  let activeTurnController = null;
3534
3608
  let slashMenu = null;
3535
3609
  let pendingApprovalAbort = null;
3536
3610
 
3537
- output.write(`${formatHeader({ mode, cwd, chat: true }, output)}\n\n`);
3611
+ output.write(`${formatHeader({ mode, cwd, chat: true, reasoningEffort: session.reasoningEffort }, output)}\n\n`);
3538
3612
  if (logger) output.write(`${formatAuxRow('log', formatPathSubject(logger.path, output), output)}\n\n`);
3539
3613
  maybeWriteAtrisGoalBanner(output, cwd);
3540
3614
 
@@ -3577,11 +3651,21 @@ async function chat(options = {}) {
3577
3651
  if (!trimmed) return false;
3578
3652
  if (EXIT_WORDS.has(trimmed.toLowerCase())) return true;
3579
3653
 
3580
- const slash = runChatSlash(trimmed, { cwd, mode, history, approveMode: session.approveMode, isTTY: output.isTTY });
3654
+ const slash = runChatSlash(trimmed, {
3655
+ cwd,
3656
+ mode,
3657
+ history,
3658
+ approveMode: session.approveMode,
3659
+ reasoningEffort: session.reasoningEffort,
3660
+ isTTY: output.isTTY,
3661
+ });
3581
3662
  if (slash) {
3582
3663
  if (slash.type === 'exit') return true;
3583
3664
  if (slash.mode) mode = slash.mode;
3584
3665
  if (slash.approveMode) session.approveMode = slash.approveMode;
3666
+ if (Object.prototype.hasOwnProperty.call(slash, 'reasoningEffort')) {
3667
+ session.reasoningEffort = slash.reasoningEffort;
3668
+ }
3585
3669
  if (slash.type === 'clear') {
3586
3670
  history.length = 0;
3587
3671
  conversationId = `ax-${process.pid}-${Date.now().toString(36)}`;
@@ -3696,12 +3780,12 @@ async function chat(options = {}) {
3696
3780
  const pendingTaskPreview = latestPendingTaskPreview(history);
3697
3781
  const route = pendingTaskPreview ? 'cloud' : options.route;
3698
3782
  maybeWriteAtrisGoalBanner(output, cwd);
3699
- let turnRoute = options.business ? 'cloud' : resolveRoute(trimmed, { route, cwd });
3783
+ let turnRoute = options.business ? 'cloud' : resolveRoute(trimmed, { route, cwd, mode, forceLocal: options.forceLocal, forceCloud: options.forceCloud });
3700
3784
  // Same downgrade as postTurn: an auto-routed local turn with no local
3701
3785
  // backend listening becomes a cloud turn instead of a blocked preflight
3702
3786
  // that dumps localhost start instructions at a consumer. Explicit --local
3703
- // keeps the real error.
3704
- if (turnRoute === 'local' && route !== 'local' && !options.forceLocal) {
3787
+ // and --alpha stay on this checkout and show the real error.
3788
+ if (turnRoute === 'local' && !pinLocalCheckout({ ...options, route, mode })) {
3705
3789
  const probeLocal = options.localBackendProbe || localBackendReachable;
3706
3790
  if (!(await probeLocal())) turnRoute = 'cloud';
3707
3791
  }
@@ -3728,6 +3812,7 @@ async function chat(options = {}) {
3728
3812
  route,
3729
3813
  business: options.business,
3730
3814
  verify: options.verify,
3815
+ reasoningEffort: session.reasoningEffort,
3731
3816
  conversationId,
3732
3817
  turnId,
3733
3818
  approveBackendApi: options.approveBackendApi,
@@ -4653,6 +4738,8 @@ async function main() {
4653
4738
  ? 'max'
4654
4739
  : args.includes('--rapid')
4655
4740
  ? 'rapid'
4741
+ : args.includes('--alpha')
4742
+ ? 'alpha'
4656
4743
  : args.includes('--fast')
4657
4744
  ? 'fast'
4658
4745
  : args.includes('--pro')
@@ -4666,7 +4753,8 @@ async function main() {
4666
4753
  const approvals = args.includes('--approvals');
4667
4754
  const printMode = args.includes('--print') || args.includes('--headless');
4668
4755
  const forceCloud = args.includes('--cloud');
4669
- const forceLocal = args.includes('--local');
4756
+ const forceLocal = args.includes('--local')
4757
+ || (explicitLane === 'alpha' && !args.includes('--cloud') && !businessSlug);
4670
4758
 
4671
4759
  let approveId = '';
4672
4760
  const approveIdx = args.indexOf('--approve');
@@ -4696,6 +4784,22 @@ async function main() {
4696
4784
  const autoApprove = args.includes('--auto-approve');
4697
4785
  if (autoApprove) args.splice(args.indexOf('--auto-approve'), 1);
4698
4786
 
4787
+ let reasoningEffort = null;
4788
+ const effortIdx = args.indexOf('--effort');
4789
+ if (effortIdx !== -1) {
4790
+ const rawEffort = String(args[effortIdx + 1] || '').trim();
4791
+ if (!rawEffort) {
4792
+ console.error('Usage: ax --effort none|low|medium|high|xhigh|default');
4793
+ process.exit(1);
4794
+ }
4795
+ reasoningEffort = normalizeReasoningEffort(rawEffort);
4796
+ if (reasoningEffort === '' && rawEffort.toLowerCase() !== 'default') {
4797
+ console.error('Usage: ax --effort none|low|medium|high|xhigh|default');
4798
+ process.exit(1);
4799
+ }
4800
+ args.splice(effortIdx, 2);
4801
+ }
4802
+
4699
4803
  const syncGrantsFlag = args.includes('--sync-grants');
4700
4804
  if (syncGrantsFlag) args.splice(args.indexOf('--sync-grants'), 1);
4701
4805
 
@@ -4723,7 +4827,7 @@ async function main() {
4723
4827
 
4724
4828
  const route = forceCloud ? 'cloud' : forceLocal ? 'local' : 'auto';
4725
4829
  const prompt = args
4726
- .filter(arg => !['--auto', '--auto-approve', '--max', '--fast', '--rapid', '--pro', '--code-fast', '--code', '--chat', '--doctor', '--approvals', '--self-test', '--benchmark', '--print', '--headless', '--local', '--cloud', '--help', '-h'].includes(arg))
4830
+ .filter(arg => !['--auto', '--auto-approve', '--max', '--fast', '--rapid', '--alpha', '--pro', '--code-fast', '--code', '--chat', '--doctor', '--approvals', '--self-test', '--benchmark', '--print', '--headless', '--local', '--cloud', '--help', '-h', '--effort'].includes(arg))
4727
4831
  .join(' ')
4728
4832
  .trim();
4729
4833
 
@@ -4879,9 +4983,12 @@ async function main() {
4879
4983
  mode,
4880
4984
  cwd: process.cwd(),
4881
4985
  route: route === 'auto' ? undefined : route,
4986
+ forceLocal,
4987
+ forceCloud,
4882
4988
  business,
4883
4989
  verify,
4884
4990
  autoPick,
4991
+ reasoningEffort,
4885
4992
  })
4886
4993
  : { ok: false, model: modelForMode(mode), output: '', durationMs: 0, error: 'missing prompt' };
4887
4994
  // Drain stdout before exiting: process.exit right after a large write
@@ -4894,7 +5001,18 @@ async function main() {
4894
5001
  }
4895
5002
 
4896
5003
  if (!prompt || args.includes('--chat')) {
4897
- await chat({ mode, cwd: process.cwd(), route: route === 'auto' ? undefined : route, business, verify, auto: autoEnabled, autoApprove });
5004
+ await chat({
5005
+ mode,
5006
+ cwd: process.cwd(),
5007
+ route: route === 'auto' ? undefined : route,
5008
+ forceLocal,
5009
+ forceCloud,
5010
+ business,
5011
+ verify,
5012
+ auto: autoEnabled,
5013
+ autoApprove,
5014
+ reasoningEffort,
5015
+ });
4898
5016
  return;
4899
5017
  }
4900
5018
 
@@ -4904,7 +5022,16 @@ async function main() {
4904
5022
  const turnStartedAt = Date.now();
4905
5023
  let result;
4906
5024
  try {
4907
- result = await turnFunctionForMode(mode)(prompt, { mode, cwd: process.cwd(), route: route === 'auto' ? undefined : route, business, verify });
5025
+ result = await turnFunctionForMode(mode)(prompt, {
5026
+ mode,
5027
+ cwd: process.cwd(),
5028
+ route: route === 'auto' ? undefined : route,
5029
+ forceLocal,
5030
+ forceCloud,
5031
+ business,
5032
+ verify,
5033
+ reasoningEffort,
5034
+ });
4908
5035
  appendAutoOutcome(autoPick, {
4909
5036
  ok: true,
4910
5037
  model: modelForMode(mode),
@@ -5028,8 +5155,10 @@ module.exports = {
5028
5155
  messageApprovesPendingApproval,
5029
5156
  messageCancelsPendingApproval,
5030
5157
  modelForMode,
5158
+ normalizeReasoningEffort,
5031
5159
  parseSseBlock,
5032
5160
  persistPendingApproval,
5161
+ pinLocalCheckout,
5033
5162
  postApprovalExecution,
5034
5163
  postCodeFastTurn,
5035
5164
  postTurn,
@@ -5039,6 +5168,7 @@ module.exports = {
5039
5168
  renderStreamingMarkdown,
5040
5169
  renderTerminalMarkdown,
5041
5170
  resolveRoute,
5171
+ REASONING_EFFORTS,
5042
5172
  runHeadlessTurn,
5043
5173
  runBenchmark,
5044
5174
  runSelfTest,