@zachjxyz/moxie 0.3.7 → 0.3.9

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
@@ -66,7 +66,7 @@ Dependencies:
66
66
 
67
67
  Agents (from .moxie/config.toml):
68
68
  [OK] claude — 2.1.91 (Claude Code)
69
- [OK] codexcodex-cli 0.118.0
69
+ [OK] gpt-gwopenai/gpt-5.4 (AI Gateway, key stored)
70
70
 
71
71
  Project:
72
72
  [OK] .moxie/ directory found
@@ -151,7 +151,7 @@ Each phase uses round-robin rotation with randomized order. Agents independently
151
151
 
152
152
  Quorum after claude's turn:
153
153
  claude pending .moxie/phases/rfc/claude-041126-142611.md
154
- codex pending .moxie/phases/rfc/codex-041126-141850.md
154
+ gpt-gw pending -
155
155
  ── 0/2 agents reached quorum
156
156
  ```
157
157
 
@@ -161,6 +161,7 @@ Quorum after claude's turn:
161
161
  - After each turn, the agent marks whether it agrees with the current state (`reached: true`)
162
162
  - If any agent finds issues, it resets all agents to `reached: false`
163
163
  - A phase completes when all healthy agents simultaneously agree
164
+ - Agents are told how many turns remain — as the countdown decreases, they prioritize substantive issues over minor nitpicks
164
165
 
165
166
  ```
166
167
  ╔════════════════════════════════════════════════════════════╗
@@ -172,6 +173,8 @@ Quorum after claude's turn:
172
173
 
173
174
  ### Safeguards
174
175
 
176
+ **Turn pressure** — Every agent prompt includes the current turn count and how many remain. As rounds run low, agents naturally triage harder — accepting minor incompletes rather than resetting quorum over stylistic concerns.
177
+
175
178
  **Dead agent detection** — If an agent fails 2 consecutive turns (timeout, empty output, quota exhaustion), it's automatically removed from rotation. Quorum adjusts to the remaining healthy agents.
176
179
 
177
180
  ```
@@ -207,6 +210,39 @@ moxie agents List configured agents
207
210
  moxie doctor Check dependencies, agents, and project health
208
211
  ```
209
212
 
213
+ ## Cost tracking
214
+
215
+ `moxie cost` shows token usage per phase and agent:
216
+
217
+ ```
218
+ Token usage by phase:
219
+
220
+ RFC:
221
+ claude-gw 950,980 tokens
222
+ gpt-gw 505,430 tokens
223
+ qwen-gw 271,317 tokens
224
+ TOTAL 1,727,727 tokens
225
+
226
+ Grand total:
227
+ 1,727,727 tokens
228
+ ```
229
+
230
+ For gateway agents, moxie also pulls actual USD costs from the [Vercel AI Gateway Custom Reporting API](https://vercel.com/docs/ai-gateway/capabilities/custom-reporting) (requires Pro or Enterprise plan, currently in beta):
231
+
232
+ ```
233
+ Gateway cost (via Vercel AI Gateway):
234
+ claude-gw $ 5.38 (1,121,678 input + 26,964 output tokens)
235
+ gpt-gw $ 0.17 (32,021 input + 457 output tokens)
236
+ qwen-gw $ 1.27 (349,598 input + 12,723 output tokens)
237
+ TOTAL $ 6.82
238
+
239
+ Dashboard: https://vercel.com/~/ai
240
+ ```
241
+
242
+ Each `moxie init` generates a unique run ID. All gateway requests are tagged with the run ID plus `project:moxie`, `phase:<name>`, and `agent:<name>`, so costs are scoped to the exact session — no date range issues for overnight or multi-day runs.
243
+
244
+ If the reporting API is unavailable, `moxie cost` shows token counts only — you can always check your spend in the [AI Gateway dashboard](https://vercel.com/docs/ai-gateway) directly.
245
+
210
246
  ## Config
211
247
 
212
248
  After `moxie init`, your `.moxie/config.toml` looks like:
@@ -217,6 +253,7 @@ path = "spec.md"
217
253
 
218
254
  [gateway]
219
255
  endpoint = "https://ai-gateway.vercel.sh"
256
+ run_id = "run-20260411-204514-93675"
220
257
 
221
258
  [agents.claude]
222
259
  command = "claude --dangerously-skip-permissions --effort max --output-format json -p"
@@ -235,38 +272,6 @@ turn_timeout = 900
235
272
 
236
273
  Edit this file to change agents, adjust timeouts, or add custom agent commands.
237
274
 
238
- ## Cost tracking
239
-
240
- `moxie cost` shows token usage per phase and agent:
241
-
242
- ```
243
- Token usage by phase:
244
-
245
- RFC:
246
- claude 12,655,300 tokens (+1 unknown)
247
- codex 8,535,058 tokens
248
- qwen 2,484,379 tokens (+2 unknown)
249
- TOTAL 23,674,737 tokens
250
-
251
- Grand total:
252
- 23,674,737 tokens
253
- ```
254
-
255
- For gateway agents, moxie also pulls actual USD costs from the [Vercel AI Gateway Custom Reporting API](https://vercel.com/docs/ai-gateway/capabilities/custom-reporting) (requires Pro or Enterprise plan, currently in beta):
256
-
257
- ```
258
- Gateway cost (via Vercel AI Gateway):
259
- claude-gw $4.82 (1,245,890 input + 389,201 output tokens)
260
- gpt-gw $3.17 (987,654 input + 234,567 output tokens)
261
- TOTAL $7.99
262
-
263
- Dashboard: https://vercel.com/~/ai
264
- ```
265
-
266
- Gateway requests are automatically tagged with `project:moxie`, `phase:<name>`, and `agent:<name>` so you can filter and drill down in the [AI Gateway dashboard](https://vercel.com/docs/ai-gateway).
267
-
268
- If you're on the free tier or the reporting API is unavailable, `moxie cost` shows token counts only — you can always check your spend in the AI Gateway dashboard directly.
269
-
270
275
  ## Platform support
271
276
 
272
277
  | Platform | Status |
package/bin/moxie CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  set -euo pipefail
18
18
 
19
- MOXIE_VERSION="0.3.7"
19
+ MOXIE_VERSION="0.3.9"
20
20
  # Resolve symlinks (npm installs bin as a symlink)
21
21
  _self="$0"
22
22
  while [ -L "$_self" ]; do
@@ -15,7 +15,7 @@ const API_KEY = process.env.GATEWAY_API_KEY;
15
15
  const ENDPOINT = process.env.GATEWAY_ENDPOINT || 'https://ai-gateway.vercel.sh';
16
16
  const MODEL = process.env.GATEWAY_MODEL;
17
17
  const MAX_TURNS = parseInt(process.env.GATEWAY_MAX_TURNS || '50', 10);
18
- const IDLE_TIMEOUT_MS = parseInt(process.env.GATEWAY_IDLE_TIMEOUT || '120000', 10);
18
+ const IDLE_TIMEOUT_MS = parseInt(process.env.GATEWAY_IDLE_TIMEOUT || '300000', 10);
19
19
  const PHASE = process.env.GATEWAY_PHASE || 'unknown';
20
20
  const AGENT_NAME = process.env.GATEWAY_AGENT || 'unknown';
21
21
  const RUN_ID = process.env.GATEWAY_RUN_ID || '';
package/lib/phases.sh CHANGED
@@ -808,13 +808,18 @@ _phase_is_complete() {
808
808
  # Shuffle AGENT_NAMES array in-place using Fisher-Yates.
809
809
  # Compatible with Bash 3.2 (no $RANDOM % n bias issues for small arrays).
810
810
  _shuffle_agents() {
811
- local i len tmp j
811
+ local i len tmp tmp_cmd j
812
812
  len=${#AGENT_NAMES[@]}
813
813
  for (( i = len - 1; i > 0; i-- )); do
814
814
  j=$(( RANDOM % (i + 1) ))
815
+ # Swap names
815
816
  tmp="${AGENT_NAMES[$i]}"
816
817
  AGENT_NAMES[$i]="${AGENT_NAMES[$j]}"
817
818
  AGENT_NAMES[$j]="$tmp"
819
+ # Swap commands to keep in sync
820
+ eval "tmp_cmd=\"\$AGENT_CMD_$i\""
821
+ eval "AGENT_CMD_$i=\"\$AGENT_CMD_$j\""
822
+ eval "AGENT_CMD_$j=\"$tmp_cmd\""
818
823
  done
819
824
  }
820
825
 
@@ -1275,13 +1280,44 @@ _run_phase() {
1275
1280
  fi
1276
1281
  fi
1277
1282
 
1278
- # Hydrate prompt with agent name and project dir
1283
+ # Hydrate prompt with agent name, project dir, and tiered turn pressure
1284
+ local remaining=$(( max_rounds - round ))
1285
+ local pct_remaining=$(( (remaining * 100) / max_rounds ))
1286
+ local turn_pressure=""
1287
+
1288
+ if [ "$pct_remaining" -gt 60 ]; then
1289
+ # Early: full rigor, gentle awareness
1290
+ turn_pressure="This is turn $round of $max_rounds ($remaining turns remaining). Focus on thoroughness and correctness. Flag all issues you find — there is time to resolve them."
1291
+ elif [ "$pct_remaining" -gt 30 ]; then
1292
+ # Middle: triage mode
1293
+ turn_pressure="This is turn $round of $max_rounds ($remaining turns remaining). Quorum has not been reached. Prioritize issues that would cause real problems in downstream phases. Do not reset quorum over stylistic preferences, speculative concerns, or minor incompletes that agents can work around. If the draft is substantively correct, reach quorum."
1294
+ elif [ "$pct_remaining" -gt 0 ]; then
1295
+ # Late: urgency
1296
+ turn_pressure="WARNING: This is turn $round of $max_rounds — only $remaining turn(s) remaining. If quorum is not reached by turn $max_rounds, the best draft will be force-accepted AS-IS including any unresolved issues. Only reset quorum if you find a factual error that would directly cause a build failure. Accept minor gaps — they can be addressed in later phases. Reaching quorum NOW with a good-enough draft is better than running out of turns with a perfect draft that was never agreed upon."
1297
+ else
1298
+ # Final turn
1299
+ turn_pressure="FINAL TURN: This is turn $round of $max_rounds — there are no more turns after this. If you do not reach quorum now, the best available draft will be force-accepted with all current issues unresolved. Set reached: true unless there is a critical factual error that makes the draft unusable for downstream phases."
1300
+ fi
1301
+
1279
1302
  local prompt_file
1280
1303
  prompt_file=$(mktemp)
1281
1304
  sed -e "s|{{AGENT_NAME}}|$current|g" \
1282
1305
  -e "s|{{PROJECT_DIR}}|$(pwd)|g" \
1306
+ -e "s|{{TURN}}|$round|g" \
1307
+ -e "s|{{MAX_ROUNDS}}|$max_rounds|g" \
1308
+ -e "s|{{REMAINING}}|$remaining|g" \
1283
1309
  "$prompt_template" > "$prompt_file"
1284
1310
 
1311
+ # Replace multiline pressure text (sed can't do multiline easily, use temp file)
1312
+ python3 -c "
1313
+ import sys
1314
+ with open('$prompt_file', 'r') as f:
1315
+ content = f.read()
1316
+ content = content.replace('{{TURN_PRESSURE}}', '''$turn_pressure''')
1317
+ with open('$prompt_file', 'w') as f:
1318
+ f.write(content)
1319
+ " 2>/dev/null
1320
+
1285
1321
  # Run
1286
1322
  dispatch_logged "$current" "$prompt_file" "$turn_timeout" "$log_dir" "$round" "$csv" "$phase"
1287
1323
  local dispatch_rc=$?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zachjxyz/moxie",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "Run multiple AI coding agents through spec-driven phases with quorum convergence. Supports CLI agents (Claude, Codex, Qwen, Aider, Goose, Amp, Cline, Roo) and Vercel AI Gateway models.",
5
5
  "bin": {
6
6
  "moxie": "bin/moxie"
@@ -76,6 +76,10 @@ Only when EVERY agent has independently verified and agreed:
76
76
 
77
77
  Do NOT write the FINAL file unless ALL agents show `reached: true` in the ledger.
78
78
 
79
+ ## Turn Pressure
80
+
81
+ {{TURN_PRESSURE}}
82
+
79
83
  ## Rules
80
84
 
81
85
  - ALWAYS verify against actual source code, not other audits
@@ -64,6 +64,10 @@ When ALL build phases are `"complete"`:
64
64
 
65
65
  Do NOT write the FINAL file unless ALL agents show `reached: true` in the ledger.
66
66
 
67
+ ## Turn Pressure
68
+
69
+ {{TURN_PRESSURE}}
70
+
67
71
  ## Rules
68
72
 
69
73
  - Complete phases in order — never skip
@@ -53,6 +53,10 @@ Write `.moxie/phases/fix/FIX-FINAL-{MMDDyy-HHmmss}.md` with:
53
53
 
54
54
  Do NOT write the FINAL file unless ALL agents show `reached: true` in the ledger.
55
55
 
56
+ ## Turn Pressure
57
+
58
+ {{TURN_PRESSURE}}
59
+
56
60
  ## Rules
57
61
 
58
62
  - Fix highest severity issues first
@@ -57,6 +57,10 @@ self-contained implementation plan. This is the canonical build spec.
57
57
 
58
58
  Do NOT write the FINAL file unless ALL agents show `reached: true` in the ledger.
59
59
 
60
+ ## Turn Pressure
61
+
62
+ {{TURN_PRESSURE}}
63
+
60
64
  ## Rules
61
65
 
62
66
  - All file paths must be accurate against current source
@@ -80,6 +80,10 @@ If ALL agents (every agent in the config) show `reached: true`:
80
80
  - Copy the final RFC to `.moxie/spec.md` (this becomes the canonical spec for all later phases)
81
81
  - Set ledger `status` to `"rfc_final"`
82
82
 
83
+ ## Turn Pressure
84
+
85
+ {{TURN_PRESSURE}}
86
+
83
87
  ## Rules
84
88
 
85
89
  - Be EXHAUSTIVE — this RFC drives the entire pipeline. Missing details here mean gaps downstream.