claude-dev-env 8.13.0 → 8.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.agents/skills/everything-search/SKILL.md +1 -1
  2. package/.agents/skills/second-account-workers/.claude/CLAUDE.md +1 -0
  3. package/.agents/skills/second-account-workers/AGENTS.md +1 -0
  4. package/.agents/skills/second-account-workers/SKILL.md +65 -0
  5. package/.agents/skills/team-advisor/SKILL.md +1 -1
  6. package/_shared/advisor/advisor-protocol.md +19 -19
  7. package/_shared/advisor/reference/advisor-block.md +1 -1
  8. package/_shared/advisor/reference/astra-rung.md +6 -6
  9. package/_shared/advisor/reference/identity.md +4 -4
  10. package/_shared/advisor/reference/lifecycle.md +2 -2
  11. package/_shared/advisor/reference/spawn-walk-log.md +4 -4
  12. package/_shared/advisor/reference/third-party-bind.md +6 -6
  13. package/_shared/advisor/reference/warm-up.md +3 -3
  14. package/_shared/advisor/scripts/config/advisor_scripts_constants/advisor_route_constants.py +2 -2
  15. package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +3 -3
  16. package/_shared/advisor/scripts/model_tier_run_validator.py +8 -9
  17. package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +91 -91
  18. package/bin/ever-shipped-skills.mjs +1 -0
  19. package/bin/install.prompt-context.test.mjs +42 -0
  20. package/docs/DJANGO_PATTERNS.md +2 -2
  21. package/docs/TEST_QUALITY.md +1 -13
  22. package/docs/second-claude-account.md +4 -0
  23. package/hooks/hooks.json +1 -6
  24. package/hooks/session/style_reminder_prompt.py +18 -4
  25. package/hooks/session/test_style_reminder_prompt.py +57 -3
  26. package/package.json +1 -1
  27. package/rules/research-mode.md +1 -1
  28. package/scripts/claude_account_worker.py +347 -0
  29. package/scripts/claude_account_worker_process.py +169 -0
  30. package/scripts/claude_account_worker_report.py +170 -0
  31. package/scripts/dev_env_scripts_constants/claude_account_worker_constants.py +139 -0
  32. package/scripts/grok_headless_runner.py +2 -5
  33. package/scripts/subprocess_stream_text.py +28 -0
  34. package/scripts/task_usage_events.py +387 -0
  35. package/scripts/task_usage_report.py +391 -0
  36. package/scripts/test_claude_account_worker.py +331 -0
  37. package/scripts/test_task_usage_events.py +47 -0
  38. package/scripts/test_task_usage_report.py +603 -0
@@ -218,19 +218,19 @@ def test_non_object_evidence_reports_the_same_message_at_validate_and_load(
218
218
  def test_clean_single_spawn_at_top_of_slice_passes() -> None:
219
219
  run = ModelTierRun(
220
220
  own_tier="Opus",
221
- candidate_tiers=["Fable"],
222
- attempts=[{"tier": "Fable", "result": "spawned"}],
223
- selected_tier="Fable",
221
+ candidate_tiers=["Opus"],
222
+ attempts=[{"tier": "Opus", "result": "spawned"}],
223
+ selected_tier="Opus",
224
224
  )
225
225
  assert validate_model_tier_run(run) is None
226
226
 
227
227
 
228
- def test_astra_codex_bind_succeeds_after_fable_when_enabled() -> None:
228
+ def test_astra_codex_bind_succeeds_after_opus_when_enabled() -> None:
229
229
  run = ModelTierRun(
230
230
  own_tier="Opus",
231
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
231
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
232
232
  attempts=[
233
- {"tier": "Fable", "result": "unavailable"},
233
+ {"tier": "Opus", "result": "unavailable"},
234
234
  {"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
235
235
  ],
236
236
  selected_tier=ADVISOR_MODEL_TIER,
@@ -239,12 +239,12 @@ def test_astra_codex_bind_succeeds_after_fable_when_enabled() -> None:
239
239
  assert validate_model_tier_run(run) is None
240
240
 
241
241
 
242
- def test_fable_success_with_astra_enabled_stops_before_astra() -> None:
242
+ def test_opus_success_with_astra_enabled_stops_before_astra() -> None:
243
243
  run = ModelTierRun(
244
244
  own_tier="Opus",
245
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
246
- attempts=[{"tier": "Fable", "result": "spawned"}],
247
- selected_tier="Fable",
245
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
246
+ attempts=[{"tier": "Opus", "result": "spawned"}],
247
+ selected_tier="Opus",
248
248
  is_astra_enabled=True,
249
249
  )
250
250
  assert validate_model_tier_run(run) is None
@@ -253,7 +253,7 @@ def test_fable_success_with_astra_enabled_stops_before_astra() -> None:
253
253
  def test_astra_first_walk_raises_when_astra_is_enabled() -> None:
254
254
  run = ModelTierRun(
255
255
  own_tier="Opus",
256
- candidate_tiers=[ADVISOR_MODEL_TIER, "Fable"],
256
+ candidate_tiers=[ADVISOR_MODEL_TIER, "Opus"],
257
257
  attempts=[{"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN}],
258
258
  selected_tier=ADVISOR_MODEL_TIER,
259
259
  is_astra_enabled=True,
@@ -262,12 +262,12 @@ def test_astra_first_walk_raises_when_astra_is_enabled() -> None:
262
262
  validate_model_tier_run(run)
263
263
 
264
264
 
265
- def test_astra_rung_follows_fable_on_third_party_cli_floor_when_enabled() -> None:
265
+ def test_astra_rung_follows_opus_on_third_party_cli_floor_when_enabled() -> None:
266
266
  run = ModelTierRun(
267
267
  own_tier="ThirdParty",
268
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
268
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
269
269
  attempts=[
270
- {"tier": "Fable", "result": "unavailable"},
270
+ {"tier": "Opus", "result": "unavailable"},
271
271
  {"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
272
272
  ],
273
273
  selected_tier=ADVISOR_MODEL_TIER,
@@ -281,9 +281,9 @@ def test_astra_rung_follows_fable_on_third_party_cli_floor_when_enabled() -> Non
281
281
  def test_astra_codex_result_requires_astra_candidate() -> None:
282
282
  run = ModelTierRun(
283
283
  own_tier="Opus",
284
- candidate_tiers=["Fable"],
285
- attempts=[{"tier": "Fable", "result": CODEX_BIND_SUCCESS_TOKEN}],
286
- selected_tier="Fable",
284
+ candidate_tiers=["Opus"],
285
+ attempts=[{"tier": "Opus", "result": CODEX_BIND_SUCCESS_TOKEN}],
286
+ selected_tier="Opus",
287
287
  )
288
288
  with pytest.raises(ModelTierRunError):
289
289
  validate_model_tier_run(run)
@@ -292,9 +292,9 @@ def test_astra_codex_result_requires_astra_candidate() -> None:
292
292
  def test_astra_spawned_result_does_not_count_as_codex_success() -> None:
293
293
  run = ModelTierRun(
294
294
  own_tier="Opus",
295
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
295
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
296
296
  attempts=[
297
- {"tier": "Fable", "result": "unavailable"},
297
+ {"tier": "Opus", "result": "unavailable"},
298
298
  {"tier": ADVISOR_MODEL_TIER, "result": "spawned"},
299
299
  ],
300
300
  selected_tier=ADVISOR_MODEL_TIER,
@@ -304,13 +304,13 @@ def test_astra_spawned_result_does_not_count_as_codex_success() -> None:
304
304
  validate_model_tier_run(run)
305
305
 
306
306
 
307
- def test_exhausted_fable_walk_fails_closed() -> None:
307
+ def test_exhausted_opus_walk_fails_closed() -> None:
308
308
  run = ModelTierRun(
309
309
  own_tier="Opus",
310
- candidate_tiers=["Fable"],
311
- attempts=[{"tier": "Fable", "result": "unavailable"}],
310
+ candidate_tiers=["Opus"],
311
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
312
312
  selected_tier=None,
313
- fallback_reason="Fable did not bind; no advisor",
313
+ fallback_reason="Opus did not bind; no advisor",
314
314
  )
315
315
  assert validate_model_tier_run(run) is None
316
316
 
@@ -318,8 +318,8 @@ def test_exhausted_fable_walk_fails_closed() -> None:
318
318
  def test_fully_exhausted_walk_with_fallback_reason_passes() -> None:
319
319
  run = ModelTierRun(
320
320
  own_tier="Opus",
321
- candidate_tiers=["Fable"],
322
- attempts=[{"tier": "Fable", "result": "unavailable"}],
321
+ candidate_tiers=["Opus"],
322
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
323
323
  selected_tier=None,
324
324
  fallback_reason="every candidate tier failed",
325
325
  )
@@ -329,9 +329,9 @@ def test_fully_exhausted_walk_with_fallback_reason_passes() -> None:
329
329
  def test_opus_candidate_on_advisor_walk_raises() -> None:
330
330
  run = ModelTierRun(
331
331
  own_tier="Opus",
332
- candidate_tiers=["Fable", "Opus"],
333
- attempts=[{"tier": "Fable", "result": "spawned"}],
334
- selected_tier="Fable",
332
+ candidate_tiers=["Opus", "Opus"],
333
+ attempts=[{"tier": "Opus", "result": "spawned"}],
334
+ selected_tier="Opus",
335
335
  )
336
336
  with pytest.raises(ModelTierRunError):
337
337
  validate_model_tier_run(run)
@@ -340,7 +340,7 @@ def test_opus_candidate_on_advisor_walk_raises() -> None:
340
340
  def test_attempt_tier_outside_candidate_slice_raises() -> None:
341
341
  run = ModelTierRun(
342
342
  own_tier="Opus",
343
- candidate_tiers=["Fable"],
343
+ candidate_tiers=["Opus"],
344
344
  attempts=[{"tier": "Haiku", "result": "spawned"}],
345
345
  selected_tier="Haiku",
346
346
  )
@@ -351,10 +351,10 @@ def test_attempt_tier_outside_candidate_slice_raises() -> None:
351
351
  def test_attempts_out_of_ladder_order_raises() -> None:
352
352
  run = ModelTierRun(
353
353
  own_tier="Opus",
354
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
354
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
355
355
  attempts=[
356
356
  {"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
357
- {"tier": "Fable", "result": "unavailable"},
357
+ {"tier": "Opus", "result": "unavailable"},
358
358
  ],
359
359
  selected_tier=ADVISOR_MODEL_TIER,
360
360
  is_astra_enabled=True,
@@ -366,12 +366,12 @@ def test_attempts_out_of_ladder_order_raises() -> None:
366
366
  def test_selected_tier_not_first_spawned_attempt_raises() -> None:
367
367
  run = ModelTierRun(
368
368
  own_tier="Opus",
369
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
369
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
370
370
  attempts=[
371
- {"tier": "Fable", "result": "unavailable"},
371
+ {"tier": "Opus", "result": "unavailable"},
372
372
  {"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
373
373
  ],
374
- selected_tier="Fable",
374
+ selected_tier="Opus",
375
375
  is_astra_enabled=True,
376
376
  )
377
377
  with pytest.raises(
@@ -387,9 +387,9 @@ def test_selected_tier_not_first_spawned_attempt_raises() -> None:
387
387
  def test_exhausted_walk_with_non_null_selected_tier_raises() -> None:
388
388
  run = ModelTierRun(
389
389
  own_tier="Opus",
390
- candidate_tiers=["Fable"],
391
- attempts=[{"tier": "Fable", "result": "unavailable"}],
392
- selected_tier="Fable",
390
+ candidate_tiers=["Opus"],
391
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
392
+ selected_tier="Opus",
393
393
  fallback_reason="every candidate tier failed",
394
394
  )
395
395
  with pytest.raises(ModelTierRunError):
@@ -399,8 +399,8 @@ def test_exhausted_walk_with_non_null_selected_tier_raises() -> None:
399
399
  def test_exhausted_walk_missing_fallback_reason_raises() -> None:
400
400
  run = ModelTierRun(
401
401
  own_tier="Opus",
402
- candidate_tiers=["Fable"],
403
- attempts=[{"tier": "Fable", "result": "unavailable"}],
402
+ candidate_tiers=["Opus"],
403
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
404
404
  selected_tier=None,
405
405
  )
406
406
  with pytest.raises(ModelTierRunError):
@@ -421,7 +421,7 @@ def test_unknown_own_tier_raises() -> None:
421
421
  def test_empty_attempts_with_null_selected_tier_raises() -> None:
422
422
  run = ModelTierRun(
423
423
  own_tier="Opus",
424
- candidate_tiers=["Fable"],
424
+ candidate_tiers=["Opus"],
425
425
  attempts=[],
426
426
  selected_tier=None,
427
427
  fallback_reason="skipped straight to CLI fallback",
@@ -433,10 +433,10 @@ def test_empty_attempts_with_null_selected_tier_raises() -> None:
433
433
  def test_incomplete_fallback_walk_before_astra_raises() -> None:
434
434
  run = ModelTierRun(
435
435
  own_tier="Opus",
436
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
437
- attempts=[{"tier": "Fable", "result": "unavailable"}],
436
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
437
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
438
438
  selected_tier=None,
439
- fallback_reason="stopped after Fable without trying Astra",
439
+ fallback_reason="stopped after Opus without trying Astra",
440
440
  is_astra_enabled=True,
441
441
  )
442
442
  with pytest.raises(ModelTierRunError):
@@ -446,9 +446,9 @@ def test_incomplete_fallback_walk_before_astra_raises() -> None:
446
446
  def test_lowercase_own_tier_and_candidates_pass() -> None:
447
447
  run = ModelTierRun(
448
448
  own_tier="opus",
449
- candidate_tiers=["fable"],
450
- attempts=[{"tier": "fable", "result": "spawned"}],
451
- selected_tier="fable",
449
+ candidate_tiers=["opus"],
450
+ attempts=[{"tier": "opus", "result": "spawned"}],
451
+ selected_tier="opus",
452
452
  )
453
453
  assert validate_model_tier_run(run) is None
454
454
 
@@ -459,16 +459,16 @@ def test_cli_validates_json_log_file(tmp_path: Path) -> None:
459
459
  json.dumps(
460
460
  {
461
461
  "own_tier": "Opus",
462
- "candidate_tiers": ["Fable"],
463
- "attempts": [{"tier": "Fable", "result": "spawned"}],
464
- "selected_tier": "Fable",
462
+ "candidate_tiers": ["Opus"],
463
+ "attempts": [{"tier": "Opus", "result": "spawned"}],
464
+ "selected_tier": "Opus",
465
465
  }
466
466
  ),
467
467
  encoding="utf-8",
468
468
  )
469
469
  assert main([str(log_path)]) == 0
470
470
  loaded_run = load_model_tier_run_from_json_path(from_path=log_path)
471
- assert loaded_run.selected_tier == "Fable"
471
+ assert loaded_run.selected_tier == "Opus"
472
472
  assert loaded_run.host_profile == "Claude"
473
473
 
474
474
 
@@ -478,9 +478,9 @@ def test_cli_rejects_non_string_host_profile(tmp_path: Path) -> None:
478
478
  json.dumps(
479
479
  {
480
480
  "own_tier": "Opus",
481
- "candidate_tiers": ["Fable"],
482
- "attempts": [{"tier": "Fable", "result": "spawned"}],
483
- "selected_tier": "Fable",
481
+ "candidate_tiers": ["Opus"],
482
+ "attempts": [{"tier": "Opus", "result": "spawned"}],
483
+ "selected_tier": "Opus",
484
484
  "host_profile": 1,
485
485
  }
486
486
  ),
@@ -495,9 +495,9 @@ def test_cli_rejects_non_boolean_astra_enabled(tmp_path: Path) -> None:
495
495
  json.dumps(
496
496
  {
497
497
  "own_tier": "Opus",
498
- "candidate_tiers": ["Fable"],
499
- "attempts": [{"tier": "Fable", "result": "spawned"}],
500
- "selected_tier": "Fable",
498
+ "candidate_tiers": ["Opus"],
499
+ "attempts": [{"tier": "Opus", "result": "spawned"}],
500
+ "selected_tier": "Opus",
501
501
  "astra_enabled": "false",
502
502
  }
503
503
  ),
@@ -512,8 +512,8 @@ def test_cli_rejects_incomplete_fallback_log(tmp_path: Path) -> None:
512
512
  json.dumps(
513
513
  {
514
514
  "own_tier": "Opus",
515
- "candidate_tiers": ["Fable", "Astra"],
516
- "attempts": [{"tier": "Fable", "result": "unavailable"}],
515
+ "candidate_tiers": ["Opus", "Astra"],
516
+ "attempts": [{"tier": "Opus", "result": "unavailable"}],
517
517
  "selected_tier": None,
518
518
  "fallback_reason": "incomplete",
519
519
  "astra_enabled": True,
@@ -531,9 +531,9 @@ def test_cli_loads_astra_enabled_fallback_walk(tmp_path: Path) -> None:
531
531
  {
532
532
  "own_tier": "ThirdParty",
533
533
  "host_profile": "ThirdParty",
534
- "candidate_tiers": ["Fable", "Astra"],
534
+ "candidate_tiers": ["Opus", "Astra"],
535
535
  "attempts": [
536
- {"tier": "Fable", "result": "unavailable"},
536
+ {"tier": "Opus", "result": "unavailable"},
537
537
  {"tier": "Astra", "result": "codex"},
538
538
  ],
539
539
  "selected_tier": "Astra",
@@ -552,12 +552,12 @@ def test_cli_missing_path_returns_usage_exit_code() -> None:
552
552
  assert main([]) == 2
553
553
 
554
554
 
555
- def test_cli_bind_at_fable_passes() -> None:
555
+ def test_cli_bind_at_opus_passes() -> None:
556
556
  run = ModelTierRun(
557
557
  own_tier="Opus",
558
- candidate_tiers=["Fable"],
559
- attempts=[{"tier": "Fable", "result": "cli"}],
560
- selected_tier="Fable",
558
+ candidate_tiers=["Opus"],
559
+ attempts=[{"tier": "Opus", "result": "cli"}],
560
+ selected_tier="Opus",
561
561
  )
562
562
  assert validate_model_tier_run(run) is None
563
563
 
@@ -565,9 +565,9 @@ def test_cli_bind_at_fable_passes() -> None:
565
565
  def test_cli_bind_fallthrough_to_opus_raises() -> None:
566
566
  run = ModelTierRun(
567
567
  own_tier="Opus",
568
- candidate_tiers=["Fable", "Opus"],
568
+ candidate_tiers=["Opus", "Opus"],
569
569
  attempts=[
570
- {"tier": "Fable", "result": "unavailable"},
570
+ {"tier": "Opus", "result": "unavailable"},
571
571
  {"tier": "Opus", "result": "cli"},
572
572
  ],
573
573
  selected_tier="Opus",
@@ -576,12 +576,12 @@ def test_cli_bind_fallthrough_to_opus_raises() -> None:
576
576
  validate_model_tier_run(run)
577
577
 
578
578
 
579
- def test_third_party_own_tier_maps_to_fable_cli_bind_passes() -> None:
579
+ def test_third_party_own_tier_maps_to_opus_cli_bind_passes() -> None:
580
580
  run = ModelTierRun(
581
581
  own_tier="ThirdParty",
582
- candidate_tiers=["Fable"],
583
- attempts=[{"tier": "Fable", "result": "cli"}],
584
- selected_tier="Fable",
582
+ candidate_tiers=["Opus"],
583
+ attempts=[{"tier": "Opus", "result": "cli"}],
584
+ selected_tier="Opus",
585
585
  )
586
586
  assert validate_model_tier_run(run) is None
587
587
 
@@ -589,9 +589,9 @@ def test_third_party_own_tier_maps_to_fable_cli_bind_passes() -> None:
589
589
  def test_third_party_own_tier_lowercase_cli_bind_passes() -> None:
590
590
  run = ModelTierRun(
591
591
  own_tier="thirdparty",
592
- candidate_tiers=["fable"],
593
- attempts=[{"tier": "fable", "result": "cli"}],
594
- selected_tier="fable",
592
+ candidate_tiers=["opus"],
593
+ attempts=[{"tier": "opus", "result": "cli"}],
594
+ selected_tier="opus",
595
595
  )
596
596
  assert validate_model_tier_run(run) is None
597
597
 
@@ -599,9 +599,9 @@ def test_third_party_own_tier_lowercase_cli_bind_passes() -> None:
599
599
  def test_self_token_is_not_bind_success_raises() -> None:
600
600
  run = ModelTierRun(
601
601
  own_tier="Opus",
602
- candidate_tiers=["Fable"],
603
- attempts=[{"tier": "Fable", "result": "self"}],
604
- selected_tier="Fable",
602
+ candidate_tiers=["Opus"],
603
+ attempts=[{"tier": "Opus", "result": "self"}],
604
+ selected_tier="Opus",
605
605
  )
606
606
  with pytest.raises(ModelTierRunError):
607
607
  validate_model_tier_run(run)
@@ -610,9 +610,9 @@ def test_self_token_is_not_bind_success_raises() -> None:
610
610
  def test_third_party_self_token_is_not_bind_success_raises() -> None:
611
611
  run = ModelTierRun(
612
612
  own_tier="ThirdParty",
613
- candidate_tiers=["Fable"],
614
- attempts=[{"tier": "Fable", "result": "self"}],
615
- selected_tier="Fable",
613
+ candidate_tiers=["Opus"],
614
+ attempts=[{"tier": "Opus", "result": "self"}],
615
+ selected_tier="Opus",
616
616
  )
617
617
  with pytest.raises(ModelTierRunError):
618
618
  validate_model_tier_run(run)
@@ -632,8 +632,8 @@ def test_third_party_host_legacy_single_tier_self_bind_raises() -> None:
632
632
  def test_third_party_cli_exhausted_fail_closed_passes() -> None:
633
633
  run = ModelTierRun(
634
634
  own_tier="ThirdParty",
635
- candidate_tiers=["Fable"],
636
- attempts=[{"tier": "Fable", "result": "unavailable"}],
635
+ candidate_tiers=["Opus"],
636
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
637
637
  selected_tier=None,
638
638
  fallback_reason=(
639
639
  "third-party host CLI Claude-chain exhausted; fail closed"
@@ -645,8 +645,8 @@ def test_third_party_cli_exhausted_fail_closed_passes() -> None:
645
645
  def test_third_party_cli_exhausted_without_fallback_reason_raises() -> None:
646
646
  run = ModelTierRun(
647
647
  own_tier="ThirdParty",
648
- candidate_tiers=["Fable"],
649
- attempts=[{"tier": "Fable", "result": "unavailable"}],
648
+ candidate_tiers=["Opus"],
649
+ attempts=[{"tier": "Opus", "result": "unavailable"}],
650
650
  selected_tier=None,
651
651
  )
652
652
  with pytest.raises(ModelTierRunError):
@@ -656,9 +656,9 @@ def test_third_party_cli_exhausted_without_fallback_reason_raises() -> None:
656
656
  def test_third_party_cli_selected_tier_mismatch_raises() -> None:
657
657
  run = ModelTierRun(
658
658
  own_tier="ThirdParty",
659
- candidate_tiers=["Fable"],
660
- attempts=[{"tier": "Fable", "result": "cli"}],
661
- selected_tier="Opus",
659
+ candidate_tiers=["Opus"],
660
+ attempts=[{"tier": "Opus", "result": "cli"}],
661
+ selected_tier="Sonnet",
662
662
  )
663
663
  with pytest.raises(ModelTierRunError):
664
664
  validate_model_tier_run(run)
@@ -667,9 +667,9 @@ def test_third_party_cli_selected_tier_mismatch_raises() -> None:
667
667
  def test_claude_host_self_token_is_not_spawn_success_raises() -> None:
668
668
  run = ModelTierRun(
669
669
  own_tier="Opus",
670
- candidate_tiers=["Fable"],
671
- attempts=[{"tier": "Fable", "result": "self"}],
672
- selected_tier="Fable",
670
+ candidate_tiers=["Opus"],
671
+ attempts=[{"tier": "Opus", "result": "self"}],
672
+ selected_tier="Opus",
673
673
  )
674
674
  with pytest.raises(ModelTierRunError):
675
675
  validate_model_tier_run(run)
@@ -699,10 +699,10 @@ def test_codex_host_astra_codex_token_counts_as_success() -> None:
699
699
  assert validate_model_tier_run(run) is None
700
700
 
701
701
 
702
- def test_codex_host_fable_then_astra_walk_raises() -> None:
702
+ def test_codex_host_opus_then_astra_walk_raises() -> None:
703
703
  run = ModelTierRun(
704
704
  own_tier="Opus",
705
- candidate_tiers=["Fable", ADVISOR_MODEL_TIER],
705
+ candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
706
706
  attempts=[{"tier": ADVISOR_MODEL_TIER, "result": "spawned"}],
707
707
  selected_tier=ADVISOR_MODEL_TIER,
708
708
  is_astra_enabled=True,
@@ -90,6 +90,7 @@ export const EVER_SHIPPED_SKILL_NAMES = new Set([
90
90
  'reviewer-gates',
91
91
  'reviews',
92
92
  'run-claude-dev-env',
93
+ 'second-account-workers',
93
94
  'session-continuity',
94
95
  'session-log',
95
96
  'session-tidy',
@@ -0,0 +1,42 @@
1
+ import { test } from 'node:test';
2
+ import { strict as assert } from 'node:assert';
3
+ import { readFileSync } from 'node:fs';
4
+
5
+ import { mergeHooksIntoSettings } from './install.mjs';
6
+
7
+ test('reinstall replaces both prompt hooks with one ordered context hook', () => {
8
+ const hooksConfig = JSON.parse(readFileSync(new URL('../hooks/hooks.json', import.meta.url), 'utf8'));
9
+ const userCommand = 'python C:/Users/example/hooks/user_hook.py';
10
+ const settings = {
11
+ hooks: {
12
+ UserPromptSubmit: [
13
+ {
14
+ matcher: '',
15
+ hooks: [
16
+ { type: 'command', command: userCommand },
17
+ {
18
+ type: 'command',
19
+ command: 'python C:/Users/example/.claude/hooks/session/style_reminder_prompt.py',
20
+ },
21
+ {
22
+ type: 'command',
23
+ command: 'python C:/Users/example/.claude/hooks/session/skill_loaded_reminder.py',
24
+ },
25
+ ],
26
+ },
27
+ ],
28
+ },
29
+ };
30
+
31
+ mergeHooksIntoSettings(settings, hooksConfig, 'C:/Users/example/.claude', 'python');
32
+
33
+ const userPromptHooks = settings.hooks.UserPromptSubmit.flatMap(eachGroup => eachGroup.hooks);
34
+ assert.equal(userPromptHooks.length, 2);
35
+ assert.equal(userPromptHooks[0].command, userCommand);
36
+ assert.match(userPromptHooks[1].command, /style_reminder_prompt\.py --include-skill-reminder$/);
37
+ assert.doesNotMatch(userPromptHooks[1].command, /skill_loaded_reminder/);
38
+
39
+ const firstMerge = JSON.stringify(settings);
40
+ mergeHooksIntoSettings(settings, hooksConfig, 'C:/Users/example/.claude', 'python');
41
+ assert.equal(JSON.stringify(settings), firstMerge);
42
+ });
@@ -35,7 +35,7 @@
35
35
 
36
36
  ## Production Migrations (Post-Launch ONLY)
37
37
 
38
- **CRITICAL:** After launch, model changes MUST be backwards-compatible.
38
+ After launch, keep model changes backwards-compatible.
39
39
 
40
40
  **Why:** Manual migration takes 2+ minutes. New code runs against old schema during this window.
41
41
 
@@ -59,7 +59,7 @@
59
59
 
60
60
  ## API Contract Changes (Post-Launch)
61
61
 
62
- **CRITICAL:** After launch, API contract changes MUST be backwards-compatible.
62
+ After launch, keep API contract changes backwards-compatible.
63
63
 
64
64
  **Why:** Users may have old client code cached. Old clients must work with new API.
65
65
 
@@ -4,19 +4,7 @@
4
4
 
5
5
  ## Test Infrastructure Anti-Patterns
6
6
 
7
- **CRITICAL: Test helpers get over-engineered MORE than any other code.**
8
-
9
- **ALWAYS:**
10
- - Single file
11
- - Simple functions
12
- - Minimal abstractions
13
- - Pragmatic approach
14
-
15
- **NEVER:**
16
- - Multi-file packages
17
- - Cache classes
18
- - Abstractions "for future"
19
- - Rigid constraints
7
+ Test helpers drift toward over-engineering faster than production code, because nothing reviews them for size. Keep a helper to one file of plain functions with the fewest abstractions the current tests need. Add a package, a cache class, or an abstraction only when a second test needs it today.
20
8
 
21
9
  **Pre-check (MANDATORY):**
22
10
  - [ ] ONE file?
@@ -10,6 +10,10 @@ keeps its own sign-in and history.
10
10
  |---|---|
11
11
  | `scripts/claude_account_profile.py` | Links each shared entry of `~/.claude` into the profile `~/.claude-profiles/ev`, moves stale copies into `.replaced/<time>/`, and writes the `claude-ev.cmd` launcher into `~/.local/bin` |
12
12
  | `scripts/claude_account_choice.py` | Reads both accounts' 5-hour and weekly meters and prints which account a job runs on |
13
+ | `scripts/claude_account_worker.py` | Runs one headless Claude worker using the account chosen by the picker |
14
+ | `scripts/claude_account_worker_process.py` | Launches the worker process, feeds it the brief, and kills it on timeout |
15
+ | `scripts/claude_account_worker_report.py` | Builds and writes the JSON report a worker leaves behind |
16
+ | `scripts/dev_env_scripts_constants/claude_account_worker_constants.py` | The worker's flag names, defaults, exit codes, and report keys |
13
17
  | `scripts/dev_env_scripts_constants/claude_account_constants.py` | The profile name, the entries that stay per account, and the picker thresholds |
14
18
 
15
19
  The launcher sets `CLAUDE_CONFIG_DIR` to the profile and passes every argument to
package/hooks/hooks.json CHANGED
@@ -69,12 +69,7 @@
69
69
  "hooks": [
70
70
  {
71
71
  "type": "command",
72
- "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/session/style_reminder_prompt.py",
73
- "timeout": 10
74
- },
75
- {
76
- "type": "command",
77
- "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/session/skill_loaded_reminder.py",
72
+ "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/session/style_reminder_prompt.py --include-skill-reminder",
78
73
  "timeout": 10
79
74
  }
80
75
  ]
@@ -12,8 +12,8 @@
12
12
  the model sees the reminder this turn, and each turn after
13
13
 
14
14
  Claude Code and Codex CLI both read the same ``additionalContext`` shape on
15
- their ``UserPromptSubmit`` event. One script serves both. The hook prints
16
- text and stops.
15
+ their ``UserPromptSubmit`` event. The Claude hook includes the skill reminder
16
+ when its flag is present. The unflagged Codex hook prints style alone.
17
17
  """
18
18
 
19
19
  from __future__ import annotations
@@ -23,15 +23,29 @@ import sys
23
23
 
24
24
  import _path_setup # noqa: F401
25
25
 
26
+ from hooks_constants.pre_tool_use_stdin import read_hook_input_dictionary_from_stdin
26
27
  from hooks_constants.style_reminder_prompt_constants import STYLE_REMINDER_PROMPT
28
+ from skill_loaded_reminder import reminder_for
29
+
30
+
31
+ def _additional_context_for_prompt() -> str:
32
+ if "--include-skill-reminder" not in sys.argv[1:]:
33
+ return STYLE_REMINDER_PROMPT
34
+ hook_input = read_hook_input_dictionary_from_stdin()
35
+ if hook_input is None:
36
+ return STYLE_REMINDER_PROMPT
37
+ skill_reminder = reminder_for(hook_input)
38
+ if skill_reminder is None:
39
+ return STYLE_REMINDER_PROMPT
40
+ return STYLE_REMINDER_PROMPT + "\n" + skill_reminder
27
41
 
28
42
 
29
43
  def main() -> None:
30
- """Print the style reminder as UserPromptSubmit additionalContext."""
44
+ """Print ordered UserPromptSubmit additionalContext."""
31
45
  payload = {
32
46
  "hookSpecificOutput": {
33
47
  "hookEventName": "UserPromptSubmit",
34
- "additionalContext": STYLE_REMINDER_PROMPT,
48
+ "additionalContext": _additional_context_for_prompt(),
35
49
  }
36
50
  }
37
51
  sys.stdout.write(json.dumps(payload) + "\n")