loki-mode 11.3.9 → 11.5.1

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 (119) hide show
  1. package/README.md +34 -18
  2. package/SKILL.md +3 -3
  3. package/VERSION +1 -1
  4. package/agents/custom_agents.py +280 -0
  5. package/autonomy/council-v2.sh +22 -1
  6. package/autonomy/edit.sh +242 -0
  7. package/autonomy/lib/chat.sh +315 -0
  8. package/autonomy/lib/engine10-push.sh +19 -1
  9. package/autonomy/lib/help-core.sh +164 -0
  10. package/autonomy/lib/json-output.sh +38 -0
  11. package/autonomy/lib/proof-generator.py +23 -5
  12. package/autonomy/lib/proof-verify.py +607 -5
  13. package/autonomy/lib/run-summary.sh +112 -0
  14. package/autonomy/lib/setup-requirements.json +35 -0
  15. package/autonomy/loki +337 -46
  16. package/autonomy/provider-offer.sh +95 -47
  17. package/autonomy/route.sh +302 -0
  18. package/autonomy/run.sh +48 -14
  19. package/autonomy/setup-wizard.sh +170 -0
  20. package/autonomy/verify.sh +62 -3
  21. package/bin/loki +73 -18
  22. package/completions/_loki +58 -1
  23. package/completions/loki.bash +57 -5
  24. package/dashboard/__init__.py +1 -1
  25. package/docs/CLI-CORE-VERBS.md +112 -0
  26. package/docs/CLI-REFERENCE.md +9 -1
  27. package/docs/COMPARE-OPENCODE.md +94 -0
  28. package/docs/COMPONENTS.md +1 -0
  29. package/docs/EVALUATING.md +27 -0
  30. package/docs/HARNESS-INTELLIGENCE-PLAN.md +20 -0
  31. package/docs/INSTALLATION.md +56 -12
  32. package/docs/KNOWN-ISSUES.md +8 -9
  33. package/docs/PROOF-PASSPORT.md +114 -0
  34. package/docs/QUICKSTART.md +108 -0
  35. package/docs/alternative-installations.md +103 -0
  36. package/docs/cost-controls.md +139 -0
  37. package/docs/environment-variables.md +45 -2
  38. package/docs/exit-codes.md +129 -12
  39. package/docs/spec-first-intent.md +29 -0
  40. package/docs/v10/CLI-MODERN.md +11 -5
  41. package/docs/v10/ENGINE.md +32 -0
  42. package/docs/v10/GUIDE.md +270 -44
  43. package/docs/v10/OPENCODE-PARITY-PLAN.md +84 -0
  44. package/loki-ts/data/model-pricing.json +1 -0
  45. package/loki-ts/dist/loki.js +1065 -978
  46. package/mcp/__init__.py +1 -1
  47. package/package.json +2 -2
  48. package/packages/control-plane/dist/server.js +1829 -715
  49. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  50. package/plugins/loki-mode/README.md +41 -1
  51. package/plugins/loki-mode/commands/handoff.md +12 -0
  52. package/plugins/loki-mode/commands/loki-verify.md +9 -2
  53. package/plugins/loki-mode/commands/start.md +20 -0
  54. package/plugins/loki-mode/hooks/hooks.json +11 -0
  55. package/plugins/loki-mode/scripts/loki-stop-verify.sh +84 -0
  56. package/providers/claude.sh +16 -2
  57. package/providers/model_route_exec.sh +22 -0
  58. package/providers/model_routes.sh +188 -0
  59. package/skills/providers.md +13 -0
  60. package/templates/agents/planner.md +10 -0
  61. package/templates/agents/reviewer.md +10 -0
  62. package/templates/agents/tester.md +10 -0
  63. package/web-app/dist/assets/{AdminPage-QK-i_x-O.js → AdminPage-Cbu3pXL8.js} +1 -1
  64. package/web-app/dist/assets/{Avatar-DblkLNjB.js → Avatar-DGqGGcGx.js} +1 -1
  65. package/web-app/dist/assets/{Badge-DIV2ny5H.js → Badge-Bhlipt6v.js} +1 -1
  66. package/web-app/dist/assets/{Button--rePJOlQ.js → Button-CpN2sO61.js} +1 -1
  67. package/web-app/dist/assets/{CockpitPage-BZlKxpGy.js → CockpitPage-BqeDJwdL.js} +1 -1
  68. package/web-app/dist/assets/{ComparePage-3_INSVux.js → ComparePage-DUieA2ba.js} +1 -1
  69. package/web-app/dist/assets/{ErrorBoundary-DHG63CNr.js → ErrorBoundary-DTWsYrOm.js} +1 -1
  70. package/web-app/dist/assets/{EvidenceReceiptPanel-DFsBnLlO.js → EvidenceReceiptPanel-BU_B9X19.js} +1 -1
  71. package/web-app/dist/assets/{GitHubIssuesPanel-phPGah98.js → GitHubIssuesPanel-DEZoLOsP.js} +1 -1
  72. package/web-app/dist/assets/{GitHubPRsPanel-T7KQqJmx.js → GitHubPRsPanel-BEsnrq7Y.js} +1 -1
  73. package/web-app/dist/assets/{HomePage-DFjGUF5I.js → HomePage-BoUVuq7h.js} +2 -2
  74. package/web-app/dist/assets/{LoginPage-CorUid_5.js → LoginPage-CmOED7vb.js} +1 -1
  75. package/web-app/dist/assets/{MagicPage-DofbSxKD.js → MagicPage-DATZitrZ.js} +1 -1
  76. package/web-app/dist/assets/{MetricsPage-qzrhhfLC.js → MetricsPage-DGL1v0I-.js} +1 -1
  77. package/web-app/dist/assets/{NotFoundPage-BAZR0mMb.js → NotFoundPage-C2WgOjZd.js} +1 -1
  78. package/web-app/dist/assets/{ProjectPage-BOSUzG9J.js → ProjectPage-BMi1tepj.js} +3 -3
  79. package/web-app/dist/assets/{ProjectsPage-Ba0YLtzD.js → ProjectsPage-vc3y5YPh.js} +1 -1
  80. package/web-app/dist/assets/{SettingsPage-Cr10Ue2K.js → SettingsPage-kbq0Ftvi.js} +1 -1
  81. package/web-app/dist/assets/{ShowcasePage-Czn655fe.js → ShowcasePage-Bn6Q8Kbg.js} +1 -1
  82. package/web-app/dist/assets/{SystemSettingsPage-Dwjnw6Ob.js → SystemSettingsPage-Basmhs_b.js} +1 -1
  83. package/web-app/dist/assets/{TeamsPage-D8nc69Be.js → TeamsPage-BTqOc4TR.js} +1 -1
  84. package/web-app/dist/assets/{TemplatesPage-DHsaCDGv.js → TemplatesPage-2P9002VL.js} +1 -1
  85. package/web-app/dist/assets/{TerminalOutput-DBejni2a.js → TerminalOutput-CAoSPBrg.js} +1 -1
  86. package/web-app/dist/assets/{activity-B2VsBl1C.js → activity-BcWVWCqU.js} +1 -1
  87. package/web-app/dist/assets/{bell-CT77Fq2H.js → bell-CYRqqgZ6.js} +1 -1
  88. package/web-app/dist/assets/{bot-DfaWgF4H.js → bot-CU7gdn3g.js} +1 -1
  89. package/web-app/dist/assets/{check-D1yp7Ndv.js → check-DLlCpz9V.js} +1 -1
  90. package/web-app/dist/assets/{chevron-left-B6Pa8IOX.js → chevron-left-CE9Cb30C.js} +1 -1
  91. package/web-app/dist/assets/{circle-alert-D5jrL_Y7.js → circle-alert-uou4bjua.js} +1 -1
  92. package/web-app/dist/assets/{clock-DIsY_fa_.js → clock-C_dSJcDX.js} +1 -1
  93. package/web-app/dist/assets/{cloud-eGwLh1As.js → cloud-DZ22ITF6.js} +1 -1
  94. package/web-app/dist/assets/{code-xml-CGDIcZ3m.js → code-xml-BrJS0hhS.js} +1 -1
  95. package/web-app/dist/assets/{database-CWpdaykI.js → database-D2HOmxtl.js} +1 -1
  96. package/web-app/dist/assets/{dollar-sign-DZEuTCs6.js → dollar-sign-CQ1vK_6q.js} +1 -1
  97. package/web-app/dist/assets/{file-code-corner-BHBW6m9v.js → file-code-corner-w2vpGm5d.js} +1 -1
  98. package/web-app/dist/assets/{file-plus-D4h1jZSR.js → file-plus-DlF6wjkD.js} +1 -1
  99. package/web-app/dist/assets/{globe-CXdqKgwd.js → globe-Dy3lBJg1.js} +1 -1
  100. package/web-app/dist/assets/{hammer-B3YuuYI_.js → hammer-C3xIiRXN.js} +1 -1
  101. package/web-app/dist/assets/{index-BLEnboSv.js → index-4t-_IW2y.js} +3 -3
  102. package/web-app/dist/assets/{layers-Dvp5nFtw.js → layers-Y8Fs8qXI.js} +1 -1
  103. package/web-app/dist/assets/{loader-circle-DodDmIZ3.js → loader-circle-CxgN1v4m.js} +1 -1
  104. package/web-app/dist/assets/{lock-EiuaH1Ep.js → lock-DFFNbXDs.js} +1 -1
  105. package/web-app/dist/assets/{package-Cx4m2hFg.js → package-5e6qCTUg.js} +1 -1
  106. package/web-app/dist/assets/{plus-D-Sd5rpH.js → plus-C0Go_ytj.js} +1 -1
  107. package/web-app/dist/assets/{refresh-cw-C0w1cdmF.js → refresh-cw-D4i-NW3o.js} +1 -1
  108. package/web-app/dist/assets/{rotate-ccw-C_qk6MTT.js → rotate-ccw-YlKkiUW6.js} +1 -1
  109. package/web-app/dist/assets/{scroll-text-DSxiFtkc.js → scroll-text-4qXOHTap.js} +1 -1
  110. package/web-app/dist/assets/{server-NTJt7I8M.js → server-BB6zXNp9.js} +1 -1
  111. package/web-app/dist/assets/{shield-alert-HBxMQOvH.js → shield-alert-D4tzjB1H.js} +1 -1
  112. package/web-app/dist/assets/{thumbs-up-DEgsHzSD.js → thumbs-up-DZiRwdFj.js} +1 -1
  113. package/web-app/dist/assets/{trash-2-px46FnTD.js → trash-2-Dv_LkRIK.js} +1 -1
  114. package/web-app/dist/assets/{trending-down-CBosVGKa.js → trending-down-BJYp9PQe.js} +1 -1
  115. package/web-app/dist/assets/{trending-up-Dbd7zrQj.js → trending-up-BTcXLklK.js} +1 -1
  116. package/web-app/dist/assets/{upload-nhdFKAs1.js → upload-fcHqwOxr.js} +1 -1
  117. package/web-app/dist/assets/{usePolling-BgaGdinh.js → usePolling-BeJYw_4L.js} +1 -1
  118. package/web-app/dist/assets/{user-CzIihUy9.js → user-BcDwUCsO.js} +1 -1
  119. package/web-app/dist/index.html +1 -1
package/autonomy/loki CHANGED
@@ -71,6 +71,15 @@ if [ -f "$_LOKI_SCRIPT_DIR/lib/lock.sh" ]; then
71
71
  source "$_LOKI_SCRIPT_DIR/lib/lock.sh"
72
72
  fi
73
73
 
74
+ # Default per-run spend cap (single source: default_max_cost_usd in loki-ts/data/model-pricing.json,
75
+ # also read by loki-ts/src/e10ext/budget_cap.ts and autonomy/run.sh). Prints a plain number; 100 only if the file is unreadable.
76
+ loki_budget_default_usd() {
77
+ local v=""
78
+ [ -f "$_LOKI_SCRIPT_DIR/../loki-ts/data/model-pricing.json" ] && \
79
+ v="$(sed -n 's/.*"default_max_cost_usd"[[:space:]]*:[[:space:]]*\([0-9][0-9.]*\).*/\1/p' "$_LOKI_SCRIPT_DIR/../loki-ts/data/model-pricing.json" | head -1)"
80
+ printf '%s\n' "${v:-100}"
81
+ }
82
+
74
83
  # Guarded browser opener (loki_open_url). Every browser open goes through it
75
84
  # so tests, CI and non-TTY runs never pop a tab. If missing, nothing opens.
76
85
  if [ -f "$_LOKI_SCRIPT_DIR/lib/browser-open.sh" ]; then
@@ -123,6 +132,12 @@ _loki_caveman_narration_level() {
123
132
  fi
124
133
  }
125
134
 
135
+ # loki edit: one-pass small change fast path (functions-only, self-guarded).
136
+ if [ -f "$_LOKI_SCRIPT_DIR/edit.sh" ]; then
137
+ # shellcheck source=edit.sh
138
+ source "$_LOKI_SCRIPT_DIR/edit.sh"
139
+ fi
140
+
126
141
  # Quickstart guided interview (v7.29.0): provides cmd_quickstart and its
127
142
  # deterministic offline template matcher. Functions-only file (no top-level
128
143
  # command), sourced here so the dispatch case can call cmd_quickstart. Composes
@@ -1722,7 +1737,14 @@ _help_verify_dsse() {
1722
1737
  echo " 66 no signing key, or no runs"
1723
1738
  }
1724
1739
 
1740
+ # Default help screen: core verbs only. `loki help all` prints show_help_all.
1725
1741
  show_help() {
1742
+ # shellcheck source=/dev/null
1743
+ source "$_LOKI_SCRIPT_DIR/lib/help-core.sh"
1744
+ help_core_screen "$(get_version)"
1745
+ }
1746
+
1747
+ show_help_all() {
1726
1748
  local version=$(get_version)
1727
1749
  # Strip color when stdout is not a TTY (piped/redirected) so captured help
1728
1750
  # output is clean, matching the bare-loki welcome path. Local overrides only.
@@ -1735,6 +1757,7 @@ show_help() {
1735
1757
  echo "Usage: loki <command> [options]"
1736
1758
  echo ""
1737
1759
  echo "New here? Try these in order:"
1760
+ echo " loki setup One-step wizard: tools, provider login, model route, spend cap (--yes for defaults)"
1738
1761
  echo " loki welcome Friendly first-run opener (what Loki is, next steps)"
1739
1762
  echo " loki doctor Check your setup is ready (a few seconds)"
1740
1763
  echo " loki quickstart Guided first build from your idea (no PRD needed)"
@@ -1815,6 +1838,7 @@ show_help() {
1815
1838
  echo ""
1816
1839
  echo "Options for 'start':"
1817
1840
  echo " --provider NAME AI provider: claude (default), codex, cline, aider, opencode"
1841
+ echo " --model ID Model tier or route (e.g. ollama/qwen3-coder)"
1818
1842
  echo " --simple Force simple complexity tier (3 phases)"
1819
1843
  echo " --complex Force complex complexity tier (8 phases)"
1820
1844
  echo " --no-dashboard Disable web dashboard"
@@ -1823,7 +1847,7 @@ show_help() {
1823
1847
  echo " --spec FILE Run against an edited spec (written by 'loki plan <task> --spec'; see also --spec-first)"
1824
1848
  echo " --fresh-prd Regenerate the PRD from the codebase (no-PRD runs; ignores the reusable generated PRD)"
1825
1849
  echo " --compliance PRESET Enable compliance mode (default|healthcare|fintech|government)"
1826
- echo " --budget USD Set cost budget limit (display in dashboard/status)"
1850
+ echo " --budget USD Per-run cost cap in USD (default $(loki_budget_default_usd); auto-pause when exceeded; see docs/cost-controls.md)"
1827
1851
  echo " --bmad-project PATH Use BMAD Method project artifacts as input"
1828
1852
  echo " --openspec PATH Use OpenSpec change directory as input"
1829
1853
  echo " --config PATH Load settings from a config file (.yaml/.json/.env). Alias: --env-file, --vars"
@@ -1899,6 +1923,7 @@ show_help() {
1899
1923
  # missing from this list, so a new command cannot ship invisible.
1900
1924
  echo ""
1901
1925
  echo "All commands:"
1926
+ echo " agents chat diff edit models route"
1902
1927
  echo " acp agent analyze api assets audit backlog bench checkpoint (cp) ci cleanup"
1903
1928
  echo " cluster cockpit code compliance completions compound config context (ctx)"
1904
1929
  echo " cost council crash dashboard demo deploy docker docs doctor dogfood"
@@ -1908,7 +1933,7 @@ show_help() {
1908
1933
  echo " next notify onboard open optimize otel outcomes own (handoff) pause plan preview"
1909
1934
  echo " projects proof (receipt) provider quick quickstart rc remote report reset"
1910
1935
  echo " merge resume review rollback run sandbox secrets secure self-update sentrux"
1911
- echo " serve setup-skill share ship spec start state stats status steer stop"
1936
+ echo " serve setup setup-skill share ship spec start state stats status steer stop"
1912
1937
  echo " syslog telemetry template test tour trigger trust trust-metrics"
1913
1938
  echo " ultracode undo update verify version voice watch watchdog web welcome why"
1914
1939
  echo " wiki workspace worktree (wt)"
@@ -2575,7 +2600,8 @@ cmd_start() {
2575
2600
  echo " Token from LOKI_REMOTE_TOKEN / LOKI_REMOTE_TOKEN_FILE"
2576
2601
  echo " (never an argument). Env: LOKI_REMOTE_URL."
2577
2602
  echo " --provider NAME AI provider: claude (default), codex, cline, aider, opencode"
2578
- echo " --allow-haiku Enable Haiku model for the fast tier (default: disabled)"
2603
+ echo " --model NAME Model or route override (for example ollama/qwen3-coder)"
2604
+ echo " --allow-haiku Enable Haiku model for the fast tier (default: disabled)"
2579
2605
  echo " --simple Force simple complexity tier (3 phases)"
2580
2606
  echo " --complex Force complex complexity tier (8 phases)"
2581
2607
  echo " --no-dashboard Disable web dashboard"
@@ -2591,7 +2617,7 @@ cmd_start() {
2591
2617
  echo " (ignores the reusable generated PRD; aliases: --regen-prd,"
2592
2618
  echo " --regenerate-prd, --regen, or LOKI_PRD_REGEN=1)"
2593
2619
  echo " --compliance PRESET Enable compliance mode (default|healthcare|fintech|government)"
2594
- echo " --budget USD Cost budget limit (auto-pause when exceeded)"
2620
+ echo " --budget USD Per-run cost cap (default $(loki_budget_default_usd); auto-pause when exceeded)"
2595
2621
  echo " --bmad-project PATH Use BMAD Method project artifacts as input"
2596
2622
  echo " --openspec PATH Use OpenSpec change directory as input"
2597
2623
  echo " --mirofish [URL] Enable MiroFish market validation (default: localhost:5001)"
@@ -2634,7 +2660,7 @@ cmd_start() {
2634
2660
  echo " LOKI_AUTO_CONFIRM Set to 'true'/'false' to control prompts (takes precedence over CI)"
2635
2661
  echo " CI Fallback: auto-confirms when 'true' and LOKI_AUTO_CONFIRM is unset"
2636
2662
  echo " LOKI_MAX_ITERATIONS Max iteration count"
2637
- echo " LOKI_BUDGET_LIMIT Cost budget limit in USD"
2663
+ echo " LOKI_BUDGET_LIMIT Cost cap in USD (default $(loki_budget_default_usd); empty means unlimited)"
2638
2664
  echo ""
2639
2665
  echo "Examples:"
2640
2666
  echo " loki start # Interactive, analyze current dir"
@@ -3032,7 +3058,7 @@ cmd_start() {
3032
3058
  echo -e "${RED}--budget must be greater than 0 (a 0 budget pauses before any work)${NC}" >&2
3033
3059
  exit 1
3034
3060
  fi
3035
- export LOKI_BUDGET_LIMIT="$2"
3061
+ export LOKI_BUDGET_LIMIT="$2" LOKI_BUDGET_SOURCE=flag
3036
3062
  shift 2
3037
3063
  else
3038
3064
  echo -e "${RED}--budget requires a USD amount (e.g., --budget 5.00)${NC}"
@@ -3050,7 +3076,7 @@ cmd_start() {
3050
3076
  echo -e "${RED}--budget must be greater than 0 (a 0 budget pauses before any work)${NC}" >&2
3051
3077
  exit 1
3052
3078
  fi
3053
- export LOKI_BUDGET_LIMIT="$budget_val"
3079
+ export LOKI_BUDGET_LIMIT="$budget_val" LOKI_BUDGET_SOURCE=flag
3054
3080
  shift
3055
3081
  ;;
3056
3082
  # v6.84.0: explicit mode flags (override auto-detection)
@@ -3184,7 +3210,7 @@ cmd_start() {
3184
3210
  ;;
3185
3211
  -*)
3186
3212
  echo -e "${RED}Unknown option: $1${NC}"
3187
- exit 1
3213
+ exit 64
3188
3214
  ;;
3189
3215
  *)
3190
3216
  # Capture first positional arg for unified mode detection.
@@ -3939,15 +3965,8 @@ cmd_start() {
3939
3965
  if ! command -v "$effective_provider" &>/dev/null; then
3940
3966
  echo -e "${RED}Error: Provider CLI '$effective_provider' is not installed.${NC}"
3941
3967
  echo ""
3942
- echo "Install it first:"
3943
- case "$effective_provider" in
3944
- claude) echo " npm install -g @anthropic-ai/claude-code" ;;
3945
- codex) echo " npm install -g @openai/codex" ;;
3946
- cline) echo " npm install -g cline" ;;
3947
- aider) echo " pip install aider-chat" ;;
3948
- opencode) echo " npm install -g opencode-ai" ;;
3949
- *) echo " Check the provider documentation for installation." ;;
3950
- esac
3968
+ echo "Install it first (same fix as loki doctor):"
3969
+ _loki_req_fix_line "$effective_provider"
3951
3970
  echo ""
3952
3971
  echo "Check your environment: loki doctor"
3953
3972
  exit 1
@@ -5153,6 +5172,17 @@ cmd_resume() {
5153
5172
  exit 0
5154
5173
  fi
5155
5174
 
5175
+ # RECOVERY: an interrupted engine10 run is resumed at its phase by loki-ts/src/util/run_outputs.ts
5176
+ # (exit 0 resumed, 4 phase reported, 5 publish failed, anything else: nothing for it, fall through).
5177
+ if ls "$LOKI_DIR"/runs/e10-*/events.jsonl >/dev/null 2>&1; then
5178
+ local _e10_rc=0
5179
+ ( _loki_bun_delegate engine10 resume "$@" ) || _e10_rc=$?
5180
+ case "$_e10_rc" in
5181
+ 0 | 4) return 0 ;;
5182
+ 5) return 1 ;;
5183
+ esac
5184
+ fi
5185
+
5156
5186
  # Check if there is anything to resume before touching signal files
5157
5187
  local has_pause_signal=false
5158
5188
  local has_stop_signal=false
@@ -7102,8 +7132,14 @@ cmd_provider() {
7102
7132
  cmd_provider_list
7103
7133
  ;;
7104
7134
  info)
7135
+ case " $* " in
7136
+ *" --json "*) _loki_bun_delegate provider info "$@" || { echo "loki provider info --json needs bun: ${_LOKI_DELEGATE_WHY}" >&2; return 1; } ;;
7137
+ esac
7105
7138
  cmd_provider_info "$@"
7106
7139
  ;;
7140
+ matrix)
7141
+ _loki_bun_delegate provider matrix "$@" || { echo "loki provider matrix needs bun: ${_LOKI_DELEGATE_WHY}" >&2; return 1; }
7142
+ ;;
7107
7143
  models)
7108
7144
  cmd_provider_models
7109
7145
  ;;
@@ -7116,7 +7152,8 @@ cmd_provider() {
7116
7152
  echo " show Show current provider (default)"
7117
7153
  echo " set Set provider for this project"
7118
7154
  echo " list List available providers"
7119
- echo " info Show provider details"
7155
+ echo " info Show provider details (--json: capability contract)"
7156
+ echo " matrix Show the capability matrix per provider and engine"
7120
7157
  echo " models Show resolved model configuration for all providers"
7121
7158
  echo ""
7122
7159
  echo "Precedence (highest wins):"
@@ -10848,7 +10885,7 @@ cmd_run() {
10848
10885
  echo " --no-dashboard Disable web dashboard"
10849
10886
  echo " --sandbox Run in Docker sandbox (default: off; requires Docker)"
10850
10887
  echo " --no-plan Skip auto-shown PRD analysis at startup"
10851
- echo " --budget USD Set cost budget limit"
10888
+ echo " --budget USD Per-run cost cap (default $(loki_budget_default_usd))"
10852
10889
  echo ""
10853
10890
  echo "Progressive Isolation:"
10854
10891
  echo " --worktree, -w Git worktree isolation (separate branch)"
@@ -12931,6 +12968,16 @@ cmd_config() {
12931
12968
  show)
12932
12969
  cmd_config_show
12933
12970
  ;;
12971
+ list)
12972
+ # HELP slice: `config list [--json]` is `config show` (json: wrapped).
12973
+ # shellcheck source=/dev/null
12974
+ source "$_LOKI_SCRIPT_DIR/lib/json-output.sh"
12975
+ if loki_json_requested "$@"; then
12976
+ loki_json_wrap config-list cmd_config_show
12977
+ else
12978
+ cmd_config_show
12979
+ fi
12980
+ ;;
12934
12981
  init)
12935
12982
  cmd_config_init
12936
12983
  ;;
@@ -12956,9 +13003,10 @@ cmd_config() {
12956
13003
  cmd_config_validate "$@"
12957
13004
  ;;
12958
13005
  *)
12959
- echo -e "${YELLOW}Usage: loki config [show|init|edit|path|set|get|example|schema|validate]${NC}"
13006
+ echo -e "${YELLOW}Usage: loki config [show|list|init|edit|path|set|get|example|schema|validate]${NC}"
12960
13007
  echo ""
12961
13008
  echo " show Show current configuration (default)"
13009
+ echo " list [--json] Same as show; --json emits one JSON object"
12962
13010
  echo " init Create a config file from template"
12963
13011
  echo " edit Open config file in editor"
12964
13012
  echo " path Show config file paths"
@@ -13447,6 +13495,100 @@ cmd_config_path() {
13447
13495
  echo "Create a config file with: loki config init"
13448
13496
  }
13449
13497
 
13498
+ # Merge the Loki plugin into a Claude Code settings.json (loki setup-skill --claude-code).
13499
+ # Existing keys are never overwritten, invalid JSON is refused (rc 3), writes are atomic.
13500
+ _setup_skill_claude_code() {
13501
+ local print_only=0 project=0 stop=0 settings=""
13502
+ while [ $# -gt 0 ]; do
13503
+ case "$1" in
13504
+ --print) print_only=1 ;;
13505
+ --project) project=1 ;;
13506
+ --stop-hook) stop=1 ;;
13507
+ --settings) settings="${2:-}"; shift ;;
13508
+ --help|-h)
13509
+ echo "Usage: loki setup-skill --claude-code [--print] [--project] [--stop-hook] [--settings FILE]"
13510
+ echo ""
13511
+ echo "Registers the Loki plugin marketplace and enables the plugin in Claude Code"
13512
+ echo "settings (default ~/.claude/settings.json; --project uses ./.claude/settings.json)."
13513
+ echo "Merges only: existing keys are kept, invalid JSON is refused."
13514
+ echo ""
13515
+ echo " --print Print the settings snippet and change nothing"
13516
+ echo " --stop-hook Also opt in to the Stop-hook fast verifier (LOKI_STOP_VERIFY=1)"
13517
+ return 0
13518
+ ;;
13519
+ *) echo "Unknown option: $1" >&2; return 2 ;;
13520
+ esac
13521
+ shift
13522
+ done
13523
+ command -v python3 >/dev/null 2>&1 || { echo "python3 is required" >&2; return 1; }
13524
+ if [ -z "$settings" ] && [ "$print_only" -eq 0 ]; then
13525
+ if [ "$project" -eq 1 ]; then
13526
+ settings="${TARGET_DIR:-.}/.claude/settings.json"
13527
+ else
13528
+ settings="$HOME/.claude/settings.json"
13529
+ fi
13530
+ fi
13531
+ local out rc
13532
+ out="$(python3 - "$settings" "$stop" "$print_only" <<'PY'
13533
+ import json, os, sys, tempfile
13534
+ path, stop, print_only = sys.argv[1], sys.argv[2] == "1", sys.argv[3] == "1"
13535
+ want = {
13536
+ "extraKnownMarketplaces": {
13537
+ "loki-mode": {"source": {"source": "github", "repo": "asklokesh/loki-mode"}}
13538
+ },
13539
+ "enabledPlugins": {"loki-mode@loki-mode": True},
13540
+ }
13541
+ if stop:
13542
+ want["env"] = {"LOKI_STOP_VERIFY": "1"}
13543
+ if print_only:
13544
+ print(json.dumps(want, indent=2))
13545
+ sys.exit(0)
13546
+ cur = {}
13547
+ if os.path.exists(path):
13548
+ try:
13549
+ raw = open(path).read()
13550
+ cur = json.loads(raw) if raw.strip() else {}
13551
+ except Exception as e:
13552
+ print("REFUSED %s is not valid JSON (%s); fix or move it aside" % (path, e))
13553
+ sys.exit(3)
13554
+ if not isinstance(cur, dict):
13555
+ print("REFUSED %s top level is not an object" % path)
13556
+ sys.exit(3)
13557
+ added = []
13558
+ for top, kv in want.items():
13559
+ node = cur.get(top)
13560
+ if node is None:
13561
+ cur[top] = {}
13562
+ node = cur[top]
13563
+ elif not isinstance(node, dict):
13564
+ print("KEPT %s (existing value is not an object)" % top)
13565
+ continue
13566
+ for k, v in kv.items():
13567
+ if k in node:
13568
+ print("KEPT %s.%s" % (top, k))
13569
+ else:
13570
+ node[k] = v
13571
+ added.append("%s.%s" % (top, k))
13572
+ print("ADDED %s.%s" % (top, k))
13573
+ if added:
13574
+ d = os.path.dirname(os.path.abspath(path))
13575
+ os.makedirs(d, exist_ok=True)
13576
+ fd, tmp = tempfile.mkstemp(dir=d, prefix=".settings.", suffix=".tmp")
13577
+ with os.fdopen(fd, "w") as f:
13578
+ json.dump(cur, f, indent=2)
13579
+ f.write("\n")
13580
+ os.replace(tmp, path)
13581
+ else:
13582
+ print("UNCHANGED %s" % path)
13583
+ PY
13584
+ )"
13585
+ rc=$?
13586
+ printf '%s\n' "$out"
13587
+ [ "$rc" -eq 0 ] || return "$rc"
13588
+ [ "$print_only" -eq 1 ] || echo "Next: in Claude Code run /reload-plugins, then try /loki-mode:start, /loki-mode:loki-verify, /loki-mode:handoff."
13589
+ return 0
13590
+ }
13591
+
13450
13592
  # Set up skill symlinks for all providers
13451
13593
  cmd_setup_skill() {
13452
13594
  # v7.6.2 B-13 fix: --help must print help, not install skills.
@@ -13460,11 +13602,17 @@ cmd_setup_skill() {
13460
13602
  echo "skills directory: ~/.claude/skills/, ~/.codex/skills/, etc."
13461
13603
  echo ""
13462
13604
  echo "Options:"
13605
+ echo " --claude-code Merge the Loki plugin into Claude Code settings (see --claude-code --help)"
13463
13606
  echo " --help, -h Show this help and exit"
13464
13607
  echo ""
13465
13608
  echo "Side effects: writes symlinks/files under ~/.<provider>/skills/loki-mode/."
13466
13609
  return 0
13467
13610
  ;;
13611
+ --claude-code)
13612
+ shift
13613
+ _setup_skill_claude_code "$@"
13614
+ return $?
13615
+ ;;
13468
13616
  esac
13469
13617
  echo -e "${BOLD}Loki Mode Skill Setup${NC}"
13470
13618
  echo ""
@@ -14052,6 +14200,18 @@ _loki_bun_delegate() {
14052
14200
  exec "$bun_bin" "$cli" "$cmd" "$@"
14053
14201
  }
14054
14202
 
14203
+ # One-line fix for a requirement id (a provider name is an id), read from the shared
14204
+ # table autonomy/lib/setup-requirements.json so runtime errors match loki doctor.
14205
+ _loki_req_fix_line() {
14206
+ local _id="$1" _fix=""
14207
+ _fix="$(jq -r --arg id "$_id" '.requirements[] | select(.id == $id) | .fix' "${SKILL_DIR}/autonomy/lib/setup-requirements.json" 2>/dev/null | head -n 1)" || _fix=""
14208
+ if [ -n "$_fix" ]; then
14209
+ echo " $_fix"
14210
+ else
14211
+ echo " Check the provider documentation for installation."
14212
+ fi
14213
+ }
14214
+
14055
14215
  # loki doctor. The one implementation is loki-ts/src/commands/doctor.ts; this is a
14056
14216
  # delegator. Only --airgap stays in bash (_loki_airgap_audit). If the Bun route is
14057
14217
  # unavailable we print a minimal diagnostic (never a second copy of the checks).
@@ -14097,7 +14257,12 @@ cmd_doctor_json() {
14097
14257
  why="${why//\\/\\\\}"; why="${why//\"/\\\"}"
14098
14258
  fix="${fix//\\/\\\\}"; fix="${fix//\"/\\\"}"
14099
14259
  ver="${ver//\\/\\\\}"; ver="${ver//\"/\\\"}"
14100
- printf '{"loki_mode_version":"%s","checks":[],"provider_availability":null,"disk":null,"ai_provider":null,"skills":[],"sentrux":null,"memory":null,"model_catalog":null,"summary":{"passed":0,"failed":1,"warnings":0,"ok":false},"route":"unavailable","reason":"%s","fix":"%s"}\n' "$ver" "$why" "$fix"
14260
+ local reqs=null
14261
+ if declare -F loki_requirements_json >/dev/null 2>&1; then
14262
+ reqs="$(loki_requirements_json 2>/dev/null | jq -c . 2>/dev/null)" || reqs=null
14263
+ [ -n "$reqs" ] || reqs=null
14264
+ fi
14265
+ printf '{"loki_mode_version":"%s","checks":[],"provider_availability":null,"disk":null,"ai_provider":null,"skills":[],"sentrux":null,"memory":null,"model_catalog":null,"requirements":%s,"summary":{"passed":0,"failed":1,"warnings":0,"ok":false},"route":"unavailable","reason":"%s","fix":"%s"}\n' "$ver" "$reqs" "$why" "$fix"
14101
14266
  }
14102
14267
 
14103
14268
  # Architectural-drift gate (v7.5.14, opt-in).
@@ -15625,6 +15790,7 @@ cmd_quick() {
15625
15790
  echo ""
15626
15791
  echo "Runs the Loki 10 engine on one small task (no PR is opened). Best for"
15627
15792
  echo "tiny tasks."
15793
+ echo "quick = small task with the verify loop. For a single pass with no loop, use loki edit."
15628
15794
  echo ""
15629
15795
  echo "Examples:"
15630
15796
  echo " loki quick \"add dark mode to this React app\""
@@ -15654,16 +15820,7 @@ cmd_quick() {
15654
15820
  echo " loki quick \"fix the login bug in auth.js\""
15655
15821
  echo " loki quick \"add input validation to the signup form\""
15656
15822
  echo " loki quick \"write unit tests for the API endpoints\""
15657
- exit 2
15658
- fi
15659
-
15660
- # v7.29.0: provider pre-flight gate. Offer install on a TTY; print honest
15661
- # manual instructions and exit 2 on non-TTY/CI, before any spend. --help and
15662
- # the no-args usage path already returned/exited above.
15663
- if declare -f provider_offer_gate >/dev/null 2>&1; then
15664
- if ! provider_offer_gate; then
15665
- exit 2
15666
- fi
15823
+ exit 64
15667
15824
  fi
15668
15825
 
15669
15826
  # #691: drop the unified config-file aliases from the task description. The
@@ -15682,6 +15839,12 @@ cmd_quick() {
15682
15839
  --verbose|-v) if [ "$_quick_task_seen" = "false" ]; then export LOKI_VERBOSE=1; continue; fi ;;
15683
15840
  --config|--vars|--env-file) _skip_next=true; continue ;;
15684
15841
  --config=*|--vars=*|--env-file=*) continue ;;
15842
+ # LM-006: a leading unknown --flag is a usage error, never task text (a typo must not start a paid run).
15843
+ --?*) if [ "$_quick_task_seen" = "false" ] &&[[ "$_qa" != *" "* ]]; then
15844
+ echo -e "${RED}Error: unknown option: $_qa${NC}" >&2
15845
+ echo "Usage: loki quick [--verbose] \"description of what to do\"" >&2
15846
+ exit 64
15847
+ fi ;;
15685
15848
  esac
15686
15849
  _quick_task_seen=true
15687
15850
  _quick_args+=("$_qa")
@@ -15690,7 +15853,17 @@ cmd_quick() {
15690
15853
  if [ $# -eq 0 ]; then
15691
15854
  echo -e "${RED}Error: No task description provided${NC}"
15692
15855
  echo "Usage: loki quick [--verbose] \"description of what to do\""
15693
- exit 2
15856
+ exit 64
15857
+ fi
15858
+
15859
+ # v7.29.0: provider pre-flight gate. Offer install on a TTY; print honest
15860
+ # manual instructions and exit 2 on non-TTY/CI, before any spend. --help and
15861
+ # every usage error (no task, unknown option, exit 64) is decided above,
15862
+ # so a host with no provider still reports a typo as 64, not 2.
15863
+ if declare -f provider_offer_gate >/dev/null 2>&1; then
15864
+ if ! provider_offer_gate; then
15865
+ exit 2
15866
+ fi
15694
15867
  fi
15695
15868
 
15696
15869
  local task_desc="$*"
@@ -15757,14 +15930,8 @@ QPRDEOF
15757
15930
  if ! command -v "$_quick_provider" &>/dev/null; then
15758
15931
  echo -e "${RED}Error: Provider CLI '$_quick_provider' is not installed.${NC}"
15759
15932
  echo ""
15760
- echo "Install your AI provider CLI first:"
15761
- case "$_quick_provider" in
15762
- claude) echo " npm install -g @anthropic-ai/claude-code" ;;
15763
- codex) echo " npm install -g @openai/codex" ;;
15764
- cline) echo " npm install -g cline" ;;
15765
- aider) echo " pip install aider-chat" ;;
15766
- *) echo " Check the provider documentation for installation." ;;
15767
- esac
15933
+ echo "Install your AI provider CLI first (same fix as loki doctor):"
15934
+ _loki_req_fix_line "$_quick_provider"
15768
15935
  echo ""
15769
15936
  echo "Then verify: loki doctor"
15770
15937
  exit 1
@@ -17902,6 +18069,8 @@ cmd_verify() {
17902
18069
  fi
17903
18070
  # shellcheck source=/dev/null
17904
18071
  source "$verify_mod"
18072
+ # verify_main handles --json natively (evidence document on stdout, banner
18073
+ # on stderr); the generic json-output.sh wrapper must not intercept it.
17905
18074
  verify_main "$@"
17906
18075
  return $?
17907
18076
  }
@@ -20677,8 +20846,33 @@ print()
20677
20846
  # Dry-run PRD analysis and cost estimation (v6.18.0; refactored v6.81.1)
20678
20847
  # Thin wrapper around show_prd_plan() so the same analysis is reusable from
20679
20848
  # `loki start`, `loki run`, and other commands without duplicated code.
20849
+ # Read-only view of .loki/state/requirements-map.json (REQTRACE; contract: docs/spec-first-intent.md).
20850
+ _plan_show_requirements() {
20851
+ local as_json="${1:-false}" map="${LOKI_DIR:-.loki}/state/requirements-map.json"
20852
+ if [ ! -s "$map" ]; then
20853
+ if [ "$as_json" = true ]; then printf '{"error":"no requirements map","path":"%s"}\n' "$map"; return 1; fi
20854
+ echo "No requirements map at $map (written after a run that had a PRD checklist, a spec, or a multi-requirement PRD)."
20855
+ return 1
20856
+ fi
20857
+ if [ "$as_json" = true ]; then cat "$map"; return 0; fi
20858
+ LOKI_RM="$map" python3 -I -c "
20859
+ import json, os, sys
20860
+ try:
20861
+ m = json.load(open(os.environ['LOKI_RM']))
20862
+ reqs = m['requirements']
20863
+ except Exception:
20864
+ print('requirements map is unreadable: ' + os.environ['LOKI_RM']); sys.exit(1)
20865
+ cov = sum(1 for r in reqs if r.get('status') == 'covered')
20866
+ print('Requirements: %d/%d covered (revision %s)' % (cov, len(reqs), str(m.get('revision', ''))[:12]))
20867
+ for r in reqs:
20868
+ chk = (' <- ' + ', '.join(r.get('checks', []))) if r.get('checks') else ''
20869
+ print(' %s %-9s %-9s %s%s' % (r.get('id'), r.get('status'), r.get('method'), str(r.get('text', ''))[:80], chk))
20870
+ "
20871
+ }
20872
+
20680
20873
  cmd_plan() {
20681
20874
  local prd_file=""
20875
+ local show_requirements=false
20682
20876
  local show_json=false
20683
20877
  local show_verbose=false
20684
20878
 
@@ -20695,6 +20889,7 @@ cmd_plan() {
20695
20889
  echo "Options:"
20696
20890
  echo " --json Machine-readable JSON output"
20697
20891
  echo " --spec With a task: write the acceptance criteria to .loki/specs/<slug>.md for you to edit"
20892
+ echo " --requirements Print the last run's requirement-to-check map (.loki/state/requirements-map.json), read-only"
20698
20893
  echo " --verbose Show detailed per-iteration breakdown"
20699
20894
  echo " --help, -h Show this help"
20700
20895
  echo ""
@@ -20712,6 +20907,7 @@ cmd_plan() {
20712
20907
  ;;
20713
20908
  --json) show_json=true; shift ;;
20714
20909
  --verbose) show_verbose=true; shift ;;
20910
+ --requirements) show_requirements=true; shift ;;
20715
20911
  *)
20716
20912
  if [ -z "$prd_file" ]; then
20717
20913
  prd_file="$1"
@@ -20721,6 +20917,11 @@ cmd_plan() {
20721
20917
  esac
20722
20918
  done
20723
20919
 
20920
+ if [ "$show_requirements" = true ]; then
20921
+ _plan_show_requirements "$show_json"
20922
+ return $?
20923
+ fi
20924
+
20724
20925
  if [ -z "$prd_file" ]; then
20725
20926
  # Under --json, a machine consumer expects JSON on every path, including
20726
20927
  # errors -- never ANSI-colored prose. Emit a structured error to stdout.
@@ -20794,13 +20995,14 @@ _suggest_command() {
20794
20995
  ultracode council demo dogfood heal modernize import issue github init template \
20795
20996
  status stop pause resume monitor watch watchdog dashboard web open preview share \
20796
20997
  memory context ctx checkpoint state report kpis cost metrics stats logs otel \
20797
- syslog telemetry crash config provider doctor setup-skill onboard quickstart \
20998
+ syslog telemetry crash config provider doctor setup setup-skill onboard quickstart \
20798
20999
  welcome update self-update rollback merge failover cluster enterprise remote deploy docker \
20799
21000
  sandbox api mcp magic compound assets export wiki control docs explain why audit compliance \
20800
21001
  welcome update self-update rollback failover cluster enterprise remote deploy docker \
20801
21002
  sandbox api mcp acp magic compound assets export wiki control docs explain why audit compliance \
20802
21003
  secrets analyze optimize bench ci reset cleanup notify trigger voice sentrux \
20803
- worktree wt projects cp rc trust-metrics serve agent code self_update test help version"
21004
+ worktree wt projects cp rc trust-metrics serve agent code self_update test help version \
21005
+ chat route agents models edit receipt setup diff undo"
20804
21006
  local best
20805
21007
  best=$(printf '%s\n' $known | awk -v t="$typo" '
20806
21008
  function min3(a, b, c) { if (a < b) { if (a < c) return a; return c } if (b < c) return b; return c }
@@ -20968,6 +21170,32 @@ main() {
20968
21170
  quick)
20969
21171
  cmd_quick "$@"
20970
21172
  ;;
21173
+ chat)
21174
+ # shellcheck disable=SC1091
21175
+ source "$_LOKI_SCRIPT_DIR/lib/chat.sh"
21176
+ cmd_chat "$@"
21177
+ ;;
21178
+ edit)
21179
+ cmd_edit "$@"
21180
+ ;;
21181
+ diff)
21182
+ # Show what the last run changed: uncommitted changes, else the HEAD commit.
21183
+ # Extra args pass through to git (for example --stat or a path).
21184
+ if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
21185
+ echo "Usage: loki diff [git diff args]"
21186
+ echo "Show uncommitted changes; if there are none, show the latest commit."
21187
+ exit 0
21188
+ fi
21189
+ if ! git rev-parse --git-dir >/dev/null 2>&1; then
21190
+ echo "loki diff: not inside a git repository" >&2
21191
+ exit 1
21192
+ fi
21193
+ if git diff --quiet HEAD -- 2>/dev/null; then
21194
+ git show --format='%h %s' "$@" HEAD
21195
+ else
21196
+ git diff "$@" HEAD
21197
+ fi
21198
+ ;;
20971
21199
  monitor)
20972
21200
  cmd_monitor "$@"
20973
21201
  ;;
@@ -20991,6 +21219,11 @@ main() {
20991
21219
  welcome)
20992
21220
  cmd_welcome "$@"
20993
21221
  ;;
21222
+ setup)
21223
+ # shellcheck disable=SC1091
21224
+ . "${SKILL_DIR}/autonomy/setup-wizard.sh"
21225
+ cmd_setup "$@"
21226
+ ;;
20994
21227
  init)
20995
21228
  cmd_init "$@"
20996
21229
  ;;
@@ -21174,6 +21407,9 @@ main() {
21174
21407
  doctor)
21175
21408
  cmd_doctor "$@"
21176
21409
  ;;
21410
+ models)
21411
+ bash "$SKILL_DIR/providers/model_routes.sh" "$@"
21412
+ ;;
21177
21413
  sentrux)
21178
21414
  cmd_sentrux "$@"
21179
21415
  ;;
@@ -21255,6 +21491,9 @@ main() {
21255
21491
  agent)
21256
21492
  cmd_agent "$@"
21257
21493
  ;;
21494
+ agents)
21495
+ cmd_agents "$@"
21496
+ ;;
21258
21497
  template)
21259
21498
  cmd_template "$@"
21260
21499
  ;;
@@ -21401,6 +21640,10 @@ main() {
21401
21640
  # deprecated-alias table; bare help prints the grouped front page.
21402
21641
  if [ "${1:-}" = "aliases" ]; then
21403
21642
  show_help_aliases
21643
+ elif [ "${1:-}" = "all" ]; then
21644
+ show_help_all
21645
+ elif [ -n "${1:-}" ] && case "${1:-}" in providers|exit-codes) true ;; *) false ;; esac && { source "$_LOKI_SCRIPT_DIR/lib/help-core.sh"; help_topic_text "$1"; }; then
21646
+ :
21404
21647
  elif [ -n "${1:-}" ]; then
21405
21648
  # `loki help <command>` reaches the command's own help. Before
21406
21649
  # this, $1 was read only for the literal "aliases" and otherwise
@@ -21470,8 +21713,8 @@ main() {
21470
21713
  echo "Did you mean 'loki ${_suggestion}'?" >&2
21471
21714
  fi
21472
21715
  # Always point to the full command list, even with no near-miss match.
21473
- echo "Run 'loki help' to see every command." >&2
21474
- exit 1
21716
+ echo "Run 'loki help' for the core commands, 'loki help all' for every command." >&2
21717
+ exit 2
21475
21718
  ;;
21476
21719
  esac
21477
21720
  }
@@ -29495,6 +29738,28 @@ PYEOF
29495
29738
  esac
29496
29739
  }
29497
29740
 
29741
+ # User-configurable child agents: .loki/agents/<name>.md, ~/.config/loki/agents/<name>.md
29742
+ cmd_agents() {
29743
+ local sub="${1:-list}"
29744
+ case "$sub" in
29745
+ help|-h|--help)
29746
+ echo "Usage: loki agents <list|new|show|export> [args]"
29747
+ echo " list List configured agents (project overrides user)"
29748
+ echo " new <name> [--user] Scaffold .loki/agents/<name>.md (or ~/.config/loki/agents)"
29749
+ echo " Names reviewer, planner, tester copy the shipped examples"
29750
+ echo " show <name> Show one agent and its system prompt"
29751
+ echo " export --claude [--user] Write agents as Claude Code subagents (.claude/agents/)"
29752
+ echo "Council reviewers use a configured agent named reviewer, tester or security."
29753
+ return 0
29754
+ ;;
29755
+ esac
29756
+ local script_dir helper
29757
+ script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
29758
+ helper="${script_dir}/../agents/custom_agents.py"
29759
+ [ -f "$helper" ] || { echo -e "${RED}Error: agents/custom_agents.py not found${NC}"; return 1; }
29760
+ python3 -I "$helper" "$@"
29761
+ }
29762
+
29498
29763
  # Agent type dispatch (v6.7.0)
29499
29764
  cmd_agent() {
29500
29765
  local subcommand="${1:-list}"
@@ -35999,7 +36264,7 @@ PYEOF
35999
36264
  }
36000
36265
 
36001
36266
  # loki bench - head-to-head benchmark harness (R2).
36002
- # Subcommands: run <task> | vs <task> | list | verify <result.json>.
36267
+ # Subcommands: run <task> | vs <task> | list | verify <result.json> | attribution.
36003
36268
  # Thin pass-through to benchmarks/bench/run.sh (shared python core runner.py).
36004
36269
  # CREDIBILITY: Loki NEVER grades its own success. Success is decided by a
36005
36270
  # held-out acceptance command run by the grader OUTSIDE the agent (exit code).
@@ -36033,6 +36298,7 @@ cmd_bench() {
36033
36298
  echo " verify <file> Recompute task_hash + check tool versions for a result.json"
36034
36299
  echo " oracles Are the graders trustworthy? Hash-bound, no spend, no provider"
36035
36300
  echo " report <files> Build results.json + RESULTS.md from per-tool result-rows"
36301
+ echo " attribution Same-model harness attribution: raw Claude Code vs Loki (--dry-run, --execute)"
36036
36302
  echo ""
36037
36303
  echo "Options:"
36038
36304
  echo " --trials N Number of trials per tool (default 3)"
@@ -36229,7 +36495,9 @@ cmd_proof() {
36229
36495
  echo " reads UNKNOWN when it cannot be computed"
36230
36496
  echo " phases [--json] Measured phase history from real phase_change"
36231
36497
  echo " events; unrecorded boundaries read UNKNOWN"
36232
- echo " show <id> Pretty-print .loki/proofs/<id>/proof.json"
36498
+ echo " show <id> [--json] Compact reviewer summary (label, revision, checks,"
36499
+ echo " requirements, modified tests); --json prints the"
36500
+ echo " full .loki/proofs/<id>/proof.json"
36233
36501
  echo " verify <id> Re-check a receipt against the repo (tamper + drift)."
36234
36502
  echo " Exit 0 clean, 1 tamper/drift, 2 could not check,"
36235
36503
  echo " 64 usage (no id, more than one id, unknown option,"
@@ -36401,6 +36669,14 @@ PYEOF
36401
36669
  exit 0
36402
36670
  ;;
36403
36671
  show)
36672
+ local _ps_json=0 _ps_a _ps_args=()
36673
+ for _ps_a in "$@"; do
36674
+ case "$_ps_a" in
36675
+ --json) _ps_json=1 ;;
36676
+ *) _ps_args+=("$_ps_a") ;;
36677
+ esac
36678
+ done
36679
+ set -- "${_ps_args[@]+"${_ps_args[@]}"}"
36404
36680
  local id="${1:-}"
36405
36681
  if [ -z "$id" ]; then
36406
36682
  echo -e "${RED}Missing proof id.${NC} Use 'loki proof list'."
@@ -36412,6 +36688,21 @@ PYEOF
36412
36688
  echo "Use 'loki proof list' to see available proofs."
36413
36689
  exit 1
36414
36690
  fi
36691
+ if [ "$_ps_json" -eq 0 ]; then
36692
+ # Compact reviewer summary (docs/PROOF-PASSPORT.md).
36693
+ local _ps_py _ps_vr="${_LOKI_SCRIPT_DIR}/lib/proof-verify.py"
36694
+ _ps_py="$(loki_verify_tool_path python3)" || {
36695
+ echo -e "${RED}python3 is unavailable${NC}" >&2
36696
+ exit 2
36697
+ }
36698
+ local _ps_root
36699
+ _ps_root="$(loki_verify_root 2>/dev/null)" || {
36700
+ echo -e "${YELLOW}Summary unavailable (project tree not resolved; not checking the ambient cwd).${NC} Use 'loki proof show ${id} --json' for the full record." >&2
36701
+ exit 2
36702
+ }
36703
+ "$_ps_py" -E "$_ps_vr" summary "$pj" --repo "$_ps_root" --loki-dir "$loki_dir" || exit $?
36704
+ exit 0
36705
+ fi
36415
36706
  if command -v jq &>/dev/null; then
36416
36707
  jq . "$pj"
36417
36708
  else