triflux 10.43.0 → 10.44.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 (47) hide show
  1. package/README.md +2 -0
  2. package/adapters/codex/skills/tfx-harness/SKILL.md +30 -0
  3. package/adapters/codex/skills/tfx-harness/skill.json +5 -0
  4. package/bin/triflux.mjs +14 -0
  5. package/hooks/keyword-rules.json +139 -19
  6. package/hub/cli-adapter-base.mjs +11 -2
  7. package/hub/codex-adapter.mjs +3 -0
  8. package/hub/intent.mjs +24 -32
  9. package/hub/router.mjs +272 -0
  10. package/hub/schema.sql +61 -2
  11. package/hub/server.mjs +42 -0
  12. package/hub/store.mjs +577 -5
  13. package/hub/team/conductor.mjs +23 -2
  14. package/hub/team/execution-mode.mjs +12 -2
  15. package/hub/team/headless.mjs +16 -0
  16. package/hub/team/retry-state-machine.mjs +8 -3
  17. package/hub/team/swarm-hypervisor.mjs +1 -0
  18. package/hub/team/swarm-preflight.mjs +47 -0
  19. package/hub/team/synapse-http.mjs +149 -4
  20. package/hub/team/worktree-lifecycle.mjs +56 -59
  21. package/hub/tools.mjs +11 -0
  22. package/hub/workers/codex-mcp.mjs +20 -4
  23. package/hub/workers/delegator-mcp.mjs +3 -49
  24. package/package.json +2 -1
  25. package/scripts/__tests__/lint-skills.test.mjs +68 -0
  26. package/scripts/__tests__/tfx-route-node-entry.test.mjs +36 -0
  27. package/scripts/keyword-detector.mjs +55 -8
  28. package/scripts/lib/agent-route-policy.mjs +360 -0
  29. package/scripts/lib/cli-codex.mjs +22 -160
  30. package/scripts/lib/codex-profile-config.mjs +29 -3
  31. package/scripts/lib/keyword-rules.mjs +12 -0
  32. package/scripts/lint-skills.mjs +65 -0
  33. package/scripts/pack.mjs +13 -0
  34. package/scripts/release/check-packages-mirror.mjs +5 -0
  35. package/scripts/setup.mjs +94 -2
  36. package/scripts/tfx-route.mjs +14 -1
  37. package/scripts/tfx-route.sh +233 -70
  38. package/skills/tfx-harness/SKILL.md +19 -76
  39. package/skills/tfx-hub/SKILL.md +1 -1
  40. package/skills/tfx-interview/SKILL.md +3 -1
  41. package/skills/tfx-interview/skill.json +1 -13
  42. package/skills/tfx-profile/SKILL.md +25 -15
  43. package/skills/tfx-prune/SKILL.md +3 -1
  44. package/skills/tfx-prune/skill.json +1 -8
  45. package/skills/tfx-setup/SKILL.md +1 -1
  46. package/tui/codex-profile.mjs +11 -2
  47. package/tui/setup.mjs +2 -0
@@ -1253,51 +1253,39 @@ route_agent() {
1253
1253
  claude-native) CLI_CMD=""; CLI_ARGS="" ;;
1254
1254
  esac
1255
1255
 
1256
- # ── 에이전트별 상세 설정 ──
1257
- case "$agent" in
1258
- # ─── 구현 레인 ───
1259
- executor|codex)
1260
- CLI_ARGS="exec --profile gpt56_terra_high ${codex_base}"
1261
- CLI_EFFORT="gpt56_terra_high"; DEFAULT_TIMEOUT=1080; RUN_MODE="fg"; OPUS_OVERSIGHT="false" ;;
1262
- build-fixer)
1263
- # 빌드 수정 — npm/biome/test-lock 등 도메인 지식 필요. base capability 우위로 gpt56_luna_low (fast tier).
1264
- CLI_ARGS="exec --profile gpt56_luna_low ${codex_base}"
1265
- CLI_EFFORT="gpt56_luna_low"; DEFAULT_TIMEOUT=540; RUN_MODE="fg"; OPUS_OVERSIGHT="false" ;;
1266
- cleanup|deslop)
1267
- # 슬롭/정리 — 패턴 매칭 위주. GPT-5.6 family mid로 lightweight lane 통일.
1268
- CLI_ARGS="exec --profile gpt56_terra_med ${codex_base}"
1269
- CLI_EFFORT="gpt56_terra_med"; DEFAULT_TIMEOUT=540; RUN_MODE="fg"; OPUS_OVERSIGHT="false" ;;
1270
- debugger)
1271
- # 디버깅 — 깊은 코드 추적 필요, GPT-5.6 family xhigh
1272
- CLI_ARGS="exec --profile gpt56_sol_xhigh ${codex_base}"
1273
- CLI_EFFORT="gpt56_sol_xhigh"; DEFAULT_TIMEOUT=900; RUN_MODE="bg"; OPUS_OVERSIGHT="false" ;;
1274
-
1275
- # ─── 설계/분석 레인 (GPT-5.6 Sol xhigh) ───
1276
- deep-executor|architect|critic)
1277
- CLI_ARGS="exec --profile gpt56_sol_xhigh ${codex_base}"
1278
- CLI_EFFORT="gpt56_sol_xhigh"; DEFAULT_TIMEOUT=3600; RUN_MODE="bg"; OPUS_OVERSIGHT="true" ;;
1279
- planner|analyst)
1280
- CLI_ARGS="exec --profile gpt56_sol_xhigh ${codex_base}"
1281
- CLI_EFFORT="gpt56_sol_xhigh"; DEFAULT_TIMEOUT=3600; RUN_MODE="fg"; OPUS_OVERSIGHT="true" ;;
1282
-
1283
- # ─── 리뷰 레인 (GPT-5.6 Terra/Sol) ───
1284
- code-reviewer|quality-reviewer)
1285
- CLI_ARGS="exec --profile gpt56_terra_high ${codex_base} review"
1286
- CLI_EFFORT="gpt56_terra_high"; DEFAULT_TIMEOUT=1800; RUN_MODE="bg"; OPUS_OVERSIGHT="false" ;;
1287
- security-reviewer)
1288
- # 보안 = 깊은 사고 → xhigh
1289
- CLI_ARGS="exec --profile gpt56_sol_xhigh ${codex_base} review"
1290
- CLI_EFFORT="gpt56_sol_xhigh"; DEFAULT_TIMEOUT=1800; RUN_MODE="bg"; OPUS_OVERSIGHT="true" ;;
1291
-
1292
- # ─── 리서치 레인 ───
1293
- scientist|document-specialist)
1294
- CLI_ARGS="exec --profile gpt56_terra_high ${codex_base}"
1295
- CLI_EFFORT="gpt56_terra_high"; DEFAULT_TIMEOUT=1440; RUN_MODE="bg"; OPUS_OVERSIGHT="false" ;;
1296
- scientist-deep)
1297
- CLI_ARGS="exec --profile gpt56_sol_xhigh ${codex_base}"
1298
- CLI_EFFORT="gpt56_sol_xhigh"; DEFAULT_TIMEOUT=3600; RUN_MODE="bg"; OPUS_OVERSIGHT="false" ;;
1256
+ # ── Codex role policy: Node SSOT의 enum-validated TSV만 shell이 조립한다. ──
1257
+ if [[ "$CLI_TYPE" == "codex" ]]; then
1258
+ local route_dir policy_file policy_row policy_profile policy_timeout policy_mode policy_oversight policy_mcp policy_subcommand
1259
+ route_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
1260
+ policy_file="$route_dir/lib/agent-route-policy.mjs"
1261
+ if [[ ! -f "$policy_file" && -n "$TFX_PKG_ROOT" ]]; then
1262
+ policy_file="$TFX_PKG_ROOT/scripts/lib/agent-route-policy.mjs"
1263
+ fi
1264
+ if [[ ! -f "$policy_file" ]]; then
1265
+ echo "ERROR: agent route policy 미발견 (경로: $policy_file)" >&2
1266
+ exit 1
1267
+ fi
1268
+ policy_row=$("$NODE_BIN" "$policy_file" --format tsv --agent "$agent") || {
1269
+ echo "ERROR: Codex agent route policy 조회 실패: $agent" >&2
1270
+ exit 1
1271
+ }
1272
+ IFS=$'\t' read -r policy_profile policy_timeout policy_mode policy_oversight policy_mcp policy_subcommand <<< "$policy_row"
1273
+ case "$policy_profile" in gpt56_sol_xhigh|gpt56_terra_high|gpt56_terra_med|gpt56_luna_low) ;; *) echo "ERROR: invalid Codex profile policy" >&2; exit 1 ;; esac
1274
+ [[ "$policy_timeout" =~ ^[1-9][0-9]*$ ]] || { echo "ERROR: invalid Codex timeout policy" >&2; exit 1; }
1275
+ case "$policy_mode" in fg|bg) ;; *) echo "ERROR: invalid Codex run mode policy" >&2; exit 1 ;; esac
1276
+ case "$policy_oversight" in true|false) ;; *) echo "ERROR: invalid Codex oversight policy" >&2; exit 1 ;; esac
1277
+ case "$policy_mcp" in implement|analyze|review) ;; *) echo "ERROR: invalid Codex MCP hint policy" >&2; exit 1 ;; esac
1278
+ case "$policy_subcommand" in exec|review) ;; *) echo "ERROR: invalid Codex subcommand policy" >&2; exit 1 ;; esac
1279
+ CLI_ARGS="exec --profile ${policy_profile} ${codex_base}"
1280
+ [[ "$policy_subcommand" == "review" ]] && CLI_ARGS+=" review"
1281
+ CLI_EFFORT="$policy_profile"; DEFAULT_TIMEOUT="$policy_timeout"; RUN_MODE="$policy_mode"; OPUS_OVERSIGHT="$policy_oversight"
1282
+ AGENT_MCP_HINT="$policy_mcp"
1283
+ return
1284
+ fi
1299
1285
 
1300
- # ─── Antigravity CLI 레인 (Gemini CLI 후속) ───
1286
+ # ── Non-Codex provider settings ──
1287
+ case "$agent" in
1288
+ # ─── Antigravity CLI lane ───
1301
1289
  # effort 차등: agent 별 GEMINI_PROFILE 을 설정하면 run_antigravity_exec() 가
1302
1290
  # resolve_gemini_profile 로 해석해 `--model "<display name>"`을 agy_args 에
1303
1291
  # 주입한다. 우선순위는 TFX_GEMINI_PROFILE(env) > GEMINI_PROFILE(agent) > flash35.
@@ -1326,27 +1314,9 @@ route_agent() {
1326
1314
  explore|claude)
1327
1315
  CLI_EFFORT="n/a"; DEFAULT_TIMEOUT=600; RUN_MODE="fg"; OPUS_OVERSIGHT="false" ;;
1328
1316
 
1329
- # ─── 검증/테스트 ───
1330
- verifier)
1331
- CLI_ARGS="exec --profile gpt56_terra_high ${codex_base} review"
1332
- CLI_EFFORT="gpt56_terra_high"; DEFAULT_TIMEOUT=1200; RUN_MODE="fg"; OPUS_OVERSIGHT="false" ;;
1333
- test-engineer)
1334
- CLI_ARGS="exec --profile gpt56_terra_high ${codex_base}"
1335
- CLI_EFFORT="gpt56_terra_high"; DEFAULT_TIMEOUT=1200; RUN_MODE="bg"; OPUS_OVERSIGHT="false" ;;
1336
- qa-tester)
1337
- CLI_ARGS="exec --profile gpt56_terra_high ${codex_base} review"
1338
- CLI_EFFORT="gpt56_terra_high"; DEFAULT_TIMEOUT=1200; RUN_MODE="bg"; OPUS_OVERSIGHT="false" ;;
1339
-
1340
- # ─── 경량 ───
1341
- spark)
1342
- CLI_ARGS="exec --profile gpt56_luna_low ${codex_base}"
1343
- CLI_EFFORT="gpt56_luna_low"; DEFAULT_TIMEOUT=180; RUN_MODE="fg"; OPUS_OVERSIGHT="false" ;;
1344
1317
  # ─── agent-map.json에만 정의된 신규 에이전트 (CLI_TYPE별 기본값) ───
1345
1318
  *)
1346
1319
  case "$CLI_TYPE" in
1347
- codex)
1348
- CLI_ARGS="exec --profile gpt56_terra_high ${codex_base}"
1349
- CLI_EFFORT="gpt56_terra_high"; DEFAULT_TIMEOUT=1080; RUN_MODE="fg"; OPUS_OVERSIGHT="false" ;;
1350
1320
  gemini|antigravity)
1351
1321
  CLI_ARGS="--print --dangerously-skip-permissions"
1352
1322
  CLI_EFFORT="agy_v1"; DEFAULT_TIMEOUT=900; RUN_MODE="bg"; OPUS_OVERSIGHT="false" ;;
@@ -1361,6 +1331,7 @@ TFX_CLI_MODE="${TFX_CLI_MODE:-auto}"
1361
1331
  TFX_NO_CLAUDE_NATIVE="${TFX_NO_CLAUDE_NATIVE:-0}"
1362
1332
  TFX_VERIFIER_OVERRIDE="${TFX_VERIFIER_OVERRIDE:-auto}"
1363
1333
  TFX_CODEX_TRANSPORT="${TFX_CODEX_TRANSPORT:-auto}"
1334
+ TFX_CODEX_PROFILE="${TFX_CODEX_PROFILE:-auto}"
1364
1335
  # Preflight 캐시 일괄 로드 — CLI/Hub 가용성 + Codex 요금제를 환경변수로 내보냄
1365
1336
  # 하위 프로세스(스킬 포함)가 TFX_CODEX_OK, TFX_GEMINI_OK, TFX_ANTIGRAVITY_OK, TFX_HUB_OK로 즉시 참조 가능
1366
1337
  if [[ -z "${TFX_PREFLIGHT_LOADED:-}" ]]; then
@@ -1421,6 +1392,13 @@ case "$TFX_CODEX_TRANSPORT" in
1421
1392
  exit 1
1422
1393
  ;;
1423
1394
  esac
1395
+ case "$TFX_CODEX_PROFILE" in
1396
+ auto|max|ultra|gpt56_luna_low|gpt56_terra_med|gpt56_terra_high|gpt56_sol_xhigh|gpt56_sol_max|gpt56_sol_ultra) ;;
1397
+ *)
1398
+ echo "ERROR: TFX_CODEX_PROFILE 값은 auto, max, ultra 또는 canonical gpt56_* profile이어야 합니다. (현재: $TFX_CODEX_PROFILE)" >&2
1399
+ exit 1
1400
+ ;;
1401
+ esac
1424
1402
  case "$TFX_VERIFIER_OVERRIDE" in
1425
1403
  auto|claude) ;;
1426
1404
  *)
@@ -1637,6 +1615,116 @@ apply_no_claude_native_mode() {
1637
1615
  ## bridge retry-run/status exposes cliInvocation.argv for escalation-chain
1638
1616
  ## profile steps. Consume those argv directly instead of duplicating profile
1639
1617
  ## resolution here.
1618
+ resolve_safe_retry_codex_profile() {
1619
+ local profile="$1"
1620
+ case "$profile" in
1621
+ ultra|gpt56_sol_ultra|*_ultra)
1622
+ echo "gpt56_sol_max"
1623
+ return
1624
+ ;;
1625
+ gpt56_luna_low|gpt56_terra_med|gpt56_terra_high|gpt56_sol_xhigh|gpt56_sol_max)
1626
+ echo "$profile"
1627
+ return
1628
+ ;;
1629
+ esac
1630
+
1631
+ local codex_home profile_file effort
1632
+ codex_home="${CODEX_HOME:-${TFX_CODEX_HOME:-${HOME:-}/.codex}}"
1633
+ profile_file="${codex_home}/${profile}.config.toml"
1634
+ if [[ ! -f "$profile_file" ]]; then
1635
+ echo "gpt56_terra_high"
1636
+ return
1637
+ fi
1638
+ effort=$(awk -F= '
1639
+ /^[[:space:]]*model_reasoning_effort[[:space:]]*=/ {
1640
+ value=$2
1641
+ sub(/[[:space:]]*#.*/, "", value)
1642
+ gsub(/^[[:space:]"'"'']+|[[:space:]"'"'']+$/, "", value)
1643
+ print tolower(value)
1644
+ exit
1645
+ }
1646
+ ' "$profile_file" 2>/dev/null || true)
1647
+ case "$effort" in
1648
+ ultra) echo "gpt56_sol_max" ;;
1649
+ "") echo "gpt56_terra_high" ;;
1650
+ *) echo "$profile" ;;
1651
+ esac
1652
+ }
1653
+
1654
+ read_codex_profile_effort() {
1655
+ local profile="$1"
1656
+ local codex_home profile_file effort
1657
+ codex_home="${CODEX_HOME:-${TFX_CODEX_HOME:-${HOME:-}/.codex}}"
1658
+ profile_file="${codex_home}/${profile}.config.toml"
1659
+ if [[ -f "$profile_file" ]]; then
1660
+ effort=$(awk -F= '
1661
+ /^[[:space:]]*model_reasoning_effort[[:space:]]*=/ {
1662
+ value=$2
1663
+ sub(/[[:space:]]*#.*/, "", value)
1664
+ gsub(/^[[:space:]"'"'']+|[[:space:]"'"'']+$/, "", value)
1665
+ print tolower(value)
1666
+ exit
1667
+ }
1668
+ ' "$profile_file" 2>/dev/null || true)
1669
+ echo "$effort"
1670
+ return
1671
+ fi
1672
+ case "$profile" in
1673
+ *_ultra) echo "ultra" ;;
1674
+ *_max) echo "max" ;;
1675
+ *_xhigh) echo "xhigh" ;;
1676
+ *_high) echo "high" ;;
1677
+ *_med|*_medium) echo "medium" ;;
1678
+ *_low) echo "low" ;;
1679
+ *) echo "" ;;
1680
+ esac
1681
+ }
1682
+
1683
+ apply_codex_concrete_effort_guard() {
1684
+ [[ "${CLI_TYPE:-}" == "codex" ]] || return 0
1685
+
1686
+ local -a args=()
1687
+ read -r -a args <<< "$CLI_ARGS"
1688
+ local profile="" i
1689
+ for ((i = 0; i < ${#args[@]}; i++)); do
1690
+ case "${args[$i]}" in
1691
+ --profile) profile="${args[$((i + 1))]:-}" ;;
1692
+ --profile=*) profile="${args[$i]#--profile=}" ;;
1693
+ esac
1694
+ done
1695
+ [[ -n "$profile" ]] || return 0
1696
+
1697
+ local allow_ultra=0
1698
+ if [[ "$TFX_CODEX_PROFILE" == "ultra" || "$TFX_CODEX_PROFILE" == "gpt56_sol_ultra" ]]; then
1699
+ if ! is_nested_codex_runtime && [[ -z "${TFX_RETRY_SNAPSHOT:-${TFX_RETRY_SNAPSHOT_FILE:-}}" ]]; then
1700
+ case "$AGENT_TYPE" in
1701
+ deep-executor|scientist-deep) allow_ultra=1 ;;
1702
+ esac
1703
+ fi
1704
+ fi
1705
+
1706
+ local effort target_effort=""
1707
+ effort="$(read_codex_profile_effort "$profile")"
1708
+ case "$profile" in
1709
+ gpt56_sol_max) target_effort="max" ;;
1710
+ gpt56_sol_ultra)
1711
+ [[ "$allow_ultra" -eq 1 ]] && target_effort="ultra" || target_effort="max"
1712
+ ;;
1713
+ *)
1714
+ if [[ "$effort" == "ultra" ]]; then
1715
+ [[ "$allow_ultra" -eq 1 ]] && target_effort="ultra" || target_effort="max"
1716
+ fi
1717
+ ;;
1718
+ esac
1719
+ [[ -n "$target_effort" ]] || return 0
1720
+
1721
+ CLI_ARGS+=" -c model=\"gpt-5.6-sol\" -c model_reasoning_effort=\"${target_effort}\""
1722
+ CLI_EFFORT="gpt56_sol_${target_effort}"
1723
+ CODEX_MODEL_OVERRIDE="gpt-5.6-sol"
1724
+ CODEX_REASONING_EFFORT_OVERRIDE="$target_effort"
1725
+ echo "[tfx-route] final Codex effort guard: ${profile}/${effort:-unknown} -> ${target_effort}" >&2
1726
+ }
1727
+
1640
1728
  apply_retry_snapshot_cli_invocation() {
1641
1729
  [[ "${CLI_TYPE:-}" == "codex" ]] || return 0
1642
1730
 
@@ -1688,10 +1776,24 @@ apply_retry_snapshot_cli_invocation() {
1688
1776
  --profile)
1689
1777
  retry_has_profile=1
1690
1778
  retry_profile="${retry_args[$((i + 1))]:-}"
1779
+ local safe_retry_profile
1780
+ safe_retry_profile="$(resolve_safe_retry_codex_profile "$retry_profile")"
1781
+ if [[ "$safe_retry_profile" != "$retry_profile" ]]; then
1782
+ echo "[tfx-route] retry Codex profile guard: ${retry_profile} -> ${safe_retry_profile}" >&2
1783
+ retry_profile="$safe_retry_profile"
1784
+ retry_args[$((i + 1))]="$safe_retry_profile"
1785
+ fi
1691
1786
  ;;
1692
1787
  --profile=*)
1693
1788
  retry_has_profile=1
1694
1789
  retry_profile="${retry_args[$i]#--profile=}"
1790
+ local safe_retry_profile
1791
+ safe_retry_profile="$(resolve_safe_retry_codex_profile "$retry_profile")"
1792
+ if [[ "$safe_retry_profile" != "$retry_profile" ]]; then
1793
+ echo "[tfx-route] retry Codex profile guard: ${retry_profile} -> ${safe_retry_profile}" >&2
1794
+ retry_profile="$safe_retry_profile"
1795
+ retry_args[$i]="--profile=$safe_retry_profile"
1796
+ fi
1695
1797
  ;;
1696
1798
  esac
1697
1799
  done
@@ -1773,6 +1875,45 @@ apply_dynamic_routing_override() {
1773
1875
  esac
1774
1876
  }
1775
1877
 
1878
+ is_nested_codex_runtime() {
1879
+ [[ -n "${TFX_TEAM_NAME:-}" || -n "${TFX_WORKER_INDEX:-}" || -n "${TFX_WORKER_SANDBOX_SCOPE:-}" ]]
1880
+ }
1881
+
1882
+ apply_codex_profile_override() {
1883
+ [[ "$CLI_TYPE" != "codex" ]] && return
1884
+ [[ "$TFX_CODEX_PROFILE" == "auto" ]] && return
1885
+
1886
+ local requested="$TFX_CODEX_PROFILE"
1887
+ local profile="$requested"
1888
+ case "$requested" in
1889
+ max) profile="gpt56_sol_max" ;;
1890
+ ultra) profile="gpt56_sol_ultra" ;;
1891
+ esac
1892
+
1893
+ if [[ "$profile" == "gpt56_sol_ultra" ]]; then
1894
+ local downgrade_reason=""
1895
+ case "$AGENT_TYPE" in
1896
+ deep-executor|scientist-deep) ;;
1897
+ *) downgrade_reason="agent ${AGENT_TYPE} is not ultra-eligible" ;;
1898
+ esac
1899
+ if is_nested_codex_runtime; then
1900
+ downgrade_reason="nested team/worker runtime"
1901
+ fi
1902
+ if [[ -n "$downgrade_reason" ]]; then
1903
+ echo "[tfx-route] Codex ultra -> max: ${downgrade_reason}" >&2
1904
+ profile="gpt56_sol_max"
1905
+ fi
1906
+ fi
1907
+
1908
+ local codex_base
1909
+ codex_base="$(build_codex_base)"
1910
+ local review_suffix=""
1911
+ [[ "$CLI_ARGS" == *" review" ]] && review_suffix=" review"
1912
+ CLI_ARGS="exec --profile ${profile} ${codex_base}${review_suffix}"
1913
+ CLI_EFFORT="$profile"
1914
+ echo "[tfx-route] Codex profile override: ${requested} -> ${profile}" >&2
1915
+ }
1916
+
1776
1917
  apply_verifier_override() {
1777
1918
  [[ "$AGENT_TYPE" != "verifier" ]] && return
1778
1919
 
@@ -2627,17 +2768,22 @@ run_codex_exec() {
2627
2768
  if [[ "$exit_code_local" -ne 0 ]] && grep -qE "is not supported when using Codex with a ChatGPT account" "$STDERR_LOG" 2>/dev/null; then
2628
2769
  local fallback_profile=""
2629
2770
  case "$CLI_EFFORT" in
2630
- gpt56_sol_xhigh|gpt56_terra_high|gpt56_terra_med) fallback_profile="gpt56_luna_low" ;;
2771
+ gpt56_sol_ultra|gpt56_sol_max|gpt56_sol_xhigh|gpt56_terra_high|gpt56_terra_med) fallback_profile="gpt56_luna_low" ;;
2631
2772
  esac
2632
2773
  if [[ -n "$fallback_profile" ]]; then
2633
2774
  echo "[tfx-route] tier fallback: $CLI_EFFORT not supported on ChatGPT account → retry with $fallback_profile" >&2
2634
2775
  local -a new_args=()
2635
- local skip_next=0
2636
- for arg in "${codex_args[@]}"; do
2637
- if [[ "$skip_next" -eq 1 ]]; then
2638
- new_args+=("$fallback_profile"); skip_next=0
2639
- elif [[ "$arg" == "--profile" ]]; then
2640
- new_args+=("$arg"); skip_next=1
2776
+ local i arg next_arg
2777
+ for ((i = 0; i < ${#codex_args[@]}; i++)); do
2778
+ arg="${codex_args[$i]}"
2779
+ next_arg="${codex_args[$((i + 1))]:-}"
2780
+ if [[ "$arg" == "--profile" ]]; then
2781
+ new_args+=("$arg" "$fallback_profile")
2782
+ i=$((i + 1))
2783
+ elif [[ "$arg" == --profile=* ]]; then
2784
+ new_args+=("--profile=$fallback_profile")
2785
+ elif [[ "$arg" == "-c" && ( "$next_arg" == model=* || "$next_arg" == model_reasoning_effort=* ) ]]; then
2786
+ i=$((i + 1))
2641
2787
  else
2642
2788
  new_args+=("$arg")
2643
2789
  fi
@@ -2681,6 +2827,13 @@ run_codex_mcp() {
2681
2827
  "--codex-command" "$CODEX_BIN"
2682
2828
  )
2683
2829
 
2830
+ if [[ -n "${CODEX_MODEL_OVERRIDE:-}" ]]; then
2831
+ mcp_args+=("--model" "$CODEX_MODEL_OVERRIDE")
2832
+ fi
2833
+ if [[ -n "${CODEX_REASONING_EFFORT_OVERRIDE:-}" ]]; then
2834
+ mcp_args+=("--reasoning-effort" "$CODEX_REASONING_EFFORT_OVERRIDE")
2835
+ fi
2836
+
2684
2837
  if [[ -n "$CODEX_CONFIG_JSON" && "$CODEX_CONFIG_JSON" != "{}" ]]; then
2685
2838
  mcp_args+=("--config-json" "$CODEX_CONFIG_JSON")
2686
2839
  fi
@@ -2744,7 +2897,9 @@ main() {
2744
2897
  apply_plan_guard
2745
2898
  apply_verifier_override
2746
2899
  apply_dynamic_routing_override
2900
+ apply_codex_profile_override
2747
2901
  apply_retry_snapshot_cli_invocation
2902
+ apply_codex_concrete_effort_guard
2748
2903
 
2749
2904
  # CLI 경로 해석
2750
2905
  case "$CLI_CMD" in
@@ -2831,6 +2986,14 @@ ${ctx_content}
2831
2986
  # Claude 네이티브 에이전트는 이 스크립트로 처리 불가
2832
2987
  if [[ "$CLI_TYPE" == "claude-native" ]]; then
2833
2988
  if [[ -n "$TFX_TEAM_NAME" ]]; then
2989
+ local native_model native_adapter
2990
+ native_adapter="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/cli-claude.mjs"
2991
+ [[ -f "$native_adapter" ]] || native_adapter="${TFX_PKG_ROOT:-}/scripts/lib/cli-claude.mjs"
2992
+ native_model=$("$NODE_BIN" -e 'import(process.argv[1]).then(({plan}) => process.stdout.write(plan({agent: process.argv[2]}).model || ""))' "$native_adapter" "$AGENT_TYPE" 2>/dev/null)
2993
+ if [[ -z "$native_model" ]]; then
2994
+ echo "ERROR: Claude native handoff model 해석 실패: $AGENT_TYPE" >&2
2995
+ exit 1
2996
+ fi
2834
2997
  # 팀 모드: Hub에 fallback 필요 시그널 전송 후 구조화된 출력
2835
2998
  echo "[tfx-route] claude-native 역할($AGENT_TYPE)은 tfx-route.sh로 실행 불가 — Claude Agent fallback 필요" >&2
2836
2999
  team_complete_task "fallback" "claude-native 역할 실행 불가: ${AGENT_TYPE}. Claude Task(sonnet) 에이전트로 위임하세요."
@@ -2838,7 +3001,7 @@ ${ctx_content}
2838
3001
  === TFX_NEEDS_FALLBACK ===
2839
3002
  agent_type: ${AGENT_TYPE}
2840
3003
  reason: claude-native roles require Claude Agent tools (Read/Edit/Grep). tfx-route.sh cannot provide these.
2841
- action: Lead should spawn Agent(subagent_type="${AGENT_TYPE}") for this task.
3004
+ action: Lead should spawn Agent(subagent_type="${AGENT_TYPE}", model="${native_model}") for this task.
2842
3005
  task_id: ${TFX_TEAM_TASK_ID:-none}
2843
3006
  FALLBACK_EOF
2844
3007
  exit 0
@@ -2,88 +2,31 @@
2
2
  name: tfx-harness
3
3
  internal: true
4
4
  description: >
5
- 메타 라우팅 단일 진입점. 어떤 스킬/워크플로우/실행 레인으로 처리할지부터 판정해야 할 때
6
- 사용한다. '어떤 스킬 쓰지?', '스킬 추천', '스킬 라우팅', '작업 라우팅', '메타 라우팅',
7
- 'which skill', 'tfx-harness' 같은 요청에 사용. 작업 자체를 수행하는 스킬이 아니라
8
- 최소 유기적 경로를 구성해 다음 스킬로 핸드오프하는 라우터다.
5
+ 어떤 스킬·경로를 선택할지 묻는 메타 라우팅 요청에 사용한다. 실행하지 않고
6
+ canonical routing SSOT에서 branch와 즉시 owner 하나만 반환한다.
9
7
  ---
10
8
 
11
- # tfx-harness — TFX/gstack/superpowers/OMC 라우팅 하니스 (Claude 정본)
9
+ # tfx-harness — Claude adapter
12
10
 
13
- ## 계약
11
+ 스킬은 실행 엔진이 아니다. `.claude/rules/tfx-routing.md`의 D0–D11을 읽어
12
+ 사용자 intent와 확인 가능한 host capability evidence를 판정한다. 정책 표, keyword
13
+ 표, owner 매트릭스를 이 파일에 복제하지 않는다.
14
14
 
15
- 스킬은 라우팅 하니스이지 실행 엔진이 아니다.
16
-
17
- **핵심 행동: 최소 유기적 경로를 구성한 뒤 핸드오프한다.** 사용자의 작업을 분류하고,
18
- superpowers + gstack + OMC + TFX 중 가장 작은 유용한 조합을 고르고, 즉시 핸드오프
19
- 대상 스킬을 Skill tool로 invoke한다. 다운스트림 스킬이나 오케스트레이션 레인이 없을
20
- 때만 하니스가 직접 작업한다.
21
-
22
- 라우팅 정책의 SSOT는 `.claude/rules/tfx-routing.md`다. 이 스킬은 그 정책을
23
- "어느 스킬로 넘길지" 판정으로 번역할 뿐, 표를 복제하지 않는다. 충돌 시 rules 문서가 이긴다.
24
-
25
- ## 레이어 모델
26
-
27
- 네 계열을 역할별로 함께 쓴다. 한 계열이 다른 계열을 대체하지 않는다.
28
-
29
- | 레이어 | 소유 | 대표 진입점 |
30
- | --- | --- | --- |
31
- | superpowers | 방법론·품질 규율 | systematic-debugging, test-driven-development, writing-plans, verification-before-completion |
32
- | gstack | 운영 워크플로우·증거 수집 | context-save/restore, qa, review, ship, investigate |
33
- | OMC | 실행 토폴로지·지속성 | autopilot, ralph, ultrawork, team, ralplan |
34
- | TFX | 로컬 자동화·CLI 브리지 | tfx-auto, tfx-plan, tfx-analysis, tfx-find, tfx-research, tfx-qa, tfx-review, tfx-ship |
35
-
36
- 유기적 경로 문법:
37
-
38
- ```text
39
- 선행조건(복원/안전가드/소유권 탐색) -> 방법론 -> 운영 워크플로우 -> 실행 소유자 -> 검증/배포/저장
40
- ```
41
-
42
- 단계 중 하나만 **즉시 핸드오프 소유자**다. 나머지 레이어는 후속 단계 또는 제약으로 명시한다.
43
-
44
- ## 판정 절차
45
-
46
- 1. 지배적 레인 식별: 신규 계획 / 계속 / 직접 구현 / 디버그 / 리서치 / 검증 / 릴리즈 /
47
- 저장·복원 / 병렬 / 원격.
48
- 2. `.claude/rules/tfx-routing.md`의 기본 워크플로우 ladder와 행동 유형 매핑으로 경로 구성.
49
- 3. 즉시 핸드오프 소유자 하나를 선택한다. 하니스 안에서 전체 경로를 실행하지 않는다.
50
- 4. 사용자가 "어떤 스킬?"만 물었다면: 경로 + 즉시 소유자 + 한 문장 근거로 답하고 실행하지
51
- 않는다 (recommendation-only).
52
- 5. 진행 요청이거나 경로가 명백하면: Skill tool로 소유자 스킬을 invoke해 핸드오프한다.
53
- 6. 혼합 요청은 선행조건 우선: 복원 → 탐색 → 디버그 → 수정 → 리뷰/QA → ship → 저장.
54
- 7. 핸드오프 이후에는 tfx-harness를 활성 상태로 취급하지 않는다.
55
-
56
- ## CLI 정책
57
-
58
- `.claude/rules/tfx-routing.md`의 "CLI 우선순위 정책 — default = Codex"를 따른다.
59
- 구현/수정/디버그/리뷰/분석 레인의 기본 워커는 Codex(tfx-auto 경유), Antigravity는
60
- 교차 확인, Claude는 메타 라우팅·planning gate·gstack 표면·최종 수단이다.
61
- 모델명/프로파일은 이 문서에 하드코딩하지 않는다 — 프로필 설정이 SSOT다.
62
-
63
- ## 출력 형태
15
+ 반환 형식:
64
16
 
65
17
  ```text
66
18
  [tfx-harness]
67
- lane: <지배적 레인>
68
- layers: method=<superpowers|none>, workflow=<gstack|none>, orchestration=<omc|none>, automation=<tfx|none>
69
- next: <즉시 핸드오프 소유자>
70
- followups: <후속 경로, 유용할 때만>
71
- reason: <한 문장>
72
- status: dispatching | recommendation-only | blocked
19
+ branch: D<n>
20
+ owner: <exactly one immediate owner>
21
+ availability: available | unavailable | unknown
22
+ fallback_notice: <optional>
23
+ status: recommendation-only | dispatching | blocked
73
24
  ```
74
25
 
75
- ## 회귀 가드
76
-
77
- - 존재하지 않는 스킬 이름을 출력하지 않는다. 현재 세션의 available skills 목록에 있는
78
- 이름만 쓴다.
79
- - 계열이 다른 계열을 대체하게 하지 않는다: superpowers=방법론, gstack=워크플로우,
80
- OMC=오케스트레이션, TFX=자동화.
81
- - 다운스트림 소유자가 정해진 뒤에도 하니스 안에서 작업을 계속하지 않는다.
82
- - 신선한 검증 증거 없이 ship으로 라우팅하지 않는다.
83
-
84
- ## Codex twin
85
-
86
- Codex 세션용 트윈(영문, `$skill` 문법, "Claude 실행 금지" 규정 포함)은 이 저장소가 아니라
87
- Codex 사용자 환경 배포 경로(`~/.codex` 스킬 표면)로 별도 배포한다. 이 저장소의
88
- `skills/tfx-harness/SKILL.md`는 Claude Code 정본이며, 두 문서는 라우팅 표를 공유하되
89
- 호스트 규정(실행 금지 대상, 스킬 문법)만 다르다. 트윈을 이 파일로 덮어쓰지 않는다.
26
+ - 판정에는 branch 하나와 immediate owner 하나만 둔다.
27
+ - availability가 unknown이면 fallback하지 않는다. 실제 unavailable 증거가 있을 때만
28
+ `owner unavailable tfx-X fallback`을 함께 알릴 있다.
29
+ - SSOT를 읽지 못하면 추측하지 말고 `blocked: routing SSOT unavailable`을 반환한다.
30
+ - “어떤 스킬/경로?” 질문은 recommendation-only다. 명백한 진행 요청만 `/skill` 문법으로
31
+ owner에 handoff한다.
32
+ - downstream implementation agent나 model은 선택하지 않는다.
@@ -43,7 +43,7 @@ Bash("codex --profile gpt56_sol_xhigh exec --dangerously-bypass-approvals-and-sa
43
43
  # ↑ --profile은 exec 앞에, --skip-git-repo-check은 exec 뒤에
44
44
 
45
45
  # Claude 네이티브 (탐색/검증)
46
- Agent(subagent_type="oh-my-claudecode:explore", prompt="{작업}")
46
+ Agent(subagent_type="oh-my-claudecode:explore", model="haiku", prompt="{작업}")
47
47
  ```
48
48
 
49
49
  ## 커맨드
@@ -1,12 +1,14 @@
1
1
  ---
2
2
  internal: true
3
3
  name: tfx-interview
4
- description: "요구사항이 모호하거나 구현 전 명확화가 필요할 때 사용한다. 'interview', 'deep-interview', '딥인터뷰', '소크라테스', '깊이 탐색', '요구사항 분석', '인터뷰', '요구사항 정리', '뭘 만들어야 하는지 모르겠어', '명확하게 해줘' 같은 요청에 반드시 사용. 구현 시작 전 스펙을 확정하고 싶을 때 적극 활용."
4
+ description: "명시 `tfx-interview` 또는 TFX 정량·다중 CLI 요구사항 탐색을 요청할 사용한다. 무수식 일반 요구사항 명확화는 host deep-interview가 소유한다."
5
5
  argument-hint: "<구현할 주제 또는 요구사항>"
6
6
  ---
7
7
 
8
8
  # tfx-interview — Quantified Socratic Requirements Exploration
9
9
 
10
+ 라우팅 정본 D2는 `.claude/rules/tfx-routing.md`를 따른다.
11
+
10
12
  > **ARGUMENTS 처리**: 이 스킬이 `ARGUMENTS: <값>`과 함께 호출되면, 해당 값을 사용자 입력으로 취급하여
11
13
  > 워크플로우의 첫 단계 입력으로 사용한다. ARGUMENTS가 비어있거나 없으면 기존 절차대로 사용자에게 입력을 요청한다.
12
14
 
@@ -1,18 +1,6 @@
1
1
  {
2
2
  "name": "tfx-interview",
3
- "description": "요구사항이 모호하거나 구현 전 명확화가 필요할 때 사용한다. 'interview', 'deep-interview', '딥인터뷰', '소크라테스', '깊이 탐색', '요구사항 분석', '인터뷰', '요구사항 정리', '뭘 만들어야 하는지 모르겠어', '명확하게 해줘' 같은 요청에 반드시 사용. 구현 시작 전 스펙을 확정하고 싶을 때 적극 활용.",
4
- "triggers": [
5
- "interview",
6
- "deep-interview",
7
- "딥인터뷰",
8
- "소크라테스",
9
- "깊이 탐색",
10
- "요구사항 분석",
11
- "인터뷰",
12
- "요구사항 탐색",
13
- "tfx-interview",
14
- "모호성 분석"
15
- ],
3
+ "description": "명시 `tfx-interview` 또는 TFX 정량·다중 CLI 요구사항 탐색을 요청할 사용한다. 무수식 일반 요구사항 명확화는 host deep-interview가 소유한다.",
16
4
  "argument_hint": "<구현할 주제 또는 요구사항>",
17
5
  "internal": true
18
6
  }
@@ -13,7 +13,8 @@ argument-hint: "[--list] [--codex | --gemini]"
13
13
  # tfx-profile — Codex/Antigravity 프로파일 매니저
14
14
 
15
15
  > CLI 프로파일의 모델/effort를 AskUserQuestion 선택지로 관리합니다.
16
- > Codex(`~/.codex/config.toml`)와 Antigravity(`~/.gemini/triflux-profiles.json`) 모두 지원.
16
+ > Codex(`~/.codex/config.toml` + `~/.codex/<profile>.config.toml`)
17
+ > Antigravity(`~/.gemini/triflux-profiles.json`) 모두 지원.
17
18
 
18
19
  ## 워크플로우
19
20
 
@@ -36,9 +37,10 @@ options:
36
37
 
37
38
  ## Codex 워크플로우
38
39
 
39
- ### Step 1: config.toml 읽기 + 현재 상태 표시
40
+ ### Step 1: Codex 설정 읽기 + 현재 상태 표시
40
41
 
41
- `~/.codex/config.toml`을 Read 도구로 읽고 프로파일 테이블을 마크다운으로 출력한다:
42
+ `~/.codex/config.toml`의 top-level 기본값과
43
+ `~/.codex/*.config.toml` 프로파일 파일을 읽어 테이블을 출력한다:
42
44
 
43
45
  ```
44
46
  | 프로파일 | 모델 | Effort |
@@ -76,11 +78,13 @@ options:
76
78
  - label: "gpt56_terra_high" → 기본 고품질 (Recommended)
77
79
  - label: "gpt56_terra_med" → 균형형
78
80
  - label: "gpt56_luna_low" → 빠른 경량
79
- - label: "gpt56_sol_xhigh" → 최대 추론
81
+ - label: "gpt56_sol_xhigh" → 고강도 추론
82
+ - label: "gpt56_sol_max" → 최난도 단일 작업
83
+ - label: "gpt56_sol_ultra" → 최상위 자동 위임 (비중첩 전용)
80
84
  - label: "custom" → 사용자가 관리하는 프로필
81
85
  ```
82
- 3. AskUserQuestion으로 effort 선택: `low | medium | high | xhigh`
83
- 4. Edit 도구로 config.toml 수정
86
+ 3. AskUserQuestion으로 effort 선택: `low | medium | high | xhigh | max | ultra`
87
+ 4. Edit 도구로 `~/.codex/<선택한 이름>.config.toml` 수정
84
88
 
85
89
  #### 기본 모델 변경
86
90
 
@@ -88,12 +92,12 @@ options:
88
92
 
89
93
  #### 프로파일 추가/삭제
90
94
 
91
- 추가: 이름 → 모델 → effort → `[profiles.name]` 섹션 추가
92
- 삭제: 선택 → 확인 → 섹션 제거
95
+ 추가: 이름 → 모델 → effort → `~/.codex/<name>.config.toml` 생성
96
+ 삭제: 선택 → 확인 → 해당 `~/.codex/<name>.config.toml` 삭제
93
97
 
94
98
  ### Step 4: 결과 확인
95
99
 
96
- 변경된 config.toml을 다시 읽어 업데이트된 테이블 표시.
100
+ 변경된 top-level config 프로파일 파일을 다시 읽어 업데이트된 테이블 표시.
97
101
 
98
102
  ---
99
103
 
@@ -162,12 +166,14 @@ options:
162
166
 
163
167
  ## 수정 규칙
164
168
 
165
- ### Codex (config.toml)
169
+ ### Codex
166
170
 
167
171
  - **백업 필수**: 수정 전 원본 기억
168
- - **프로파일 섹션 형식**: `[profiles.name]\nmodel = "..."\nmodel_reasoning_effort = "..."`
169
- - **다른 섹션 건드리지 않기**: `[notice]`, `[features]`, `[mcp_servers.*]` 절대 수정 금지
170
- - **Edit 도구 사용**: old_string new_string으로 정확한 섹션만 치환
172
+ - **프로파일 파일 형식**: `~/.codex/<name>.config.toml` 안에
173
+ `model = "..."`와 `model_reasoning_effort = "..."`를 top-level 키로 기록
174
+ - **inline 프로파일 금지**: `config.toml`에 `[profiles.<name>]` 섹션을 추가하지 않기
175
+ - **기본값만 config.toml에서 수정**: top-level `model`,
176
+ `model_reasoning_effort` 외 `[notice]`, `[features]`, `[mcp_servers.*]` 등은 건드리지 않기
171
177
 
172
178
  ### Antigravity (triflux-profiles.json)
173
179
 
@@ -182,7 +188,9 @@ options:
182
188
  | 프로필 | 용도 |
183
189
  |------|------|
184
190
  | gpt56_terra_high | 기본 고품질 |
185
- | gpt56_sol_xhigh | 최대 추론 |
191
+ | gpt56_sol_xhigh | 고강도 추론 |
192
+ | gpt56_sol_max | 최난도 단일 작업 |
193
+ | gpt56_sol_ultra | 최상위 자동 위임 (비중첩 전용) |
186
194
  | gpt56_terra_med | 균형형 |
187
195
  | gpt56_luna_low | 빠른 경량 |
188
196
  | custom | 사용자가 관리하는 프로필 |
@@ -194,7 +202,9 @@ options:
194
202
  | low | 빠른 응답, 최소 추론 |
195
203
  | medium | 균형 잡힌 추론 |
196
204
  | high | 깊은 추론 |
197
- | xhigh | 최대 추론 (느림) |
205
+ | xhigh | 고강도 추론 |
206
+ | max | 최난도 단일 작업용 최대 추론 |
207
+ | ultra | 최대 추론 + 자동 작업 위임; 팀/스웜 내부 사용 금지 |
198
208
 
199
209
  ### Antigravity 프로필
200
210