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
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env bash
2
+ # setup-wizard.sh -- `loki setup`: the single first-run wizard.
3
+ # Sourced by autonomy/loki; relies on cmd_config_set and SKILL_DIR from that
4
+ # file. `loki welcome` (intro), `loki quickstart` (first build) and
5
+ # `loki doctor` (health) remain separate entry points.
6
+ #
7
+ # REQUIRED (doctor fails without them): node >= 20, python3 >= 3.8, jq, git, curl
8
+ # AT LEAST ONE of: a provider CLI (claude, codex, cline, aider, opencode) or the
9
+ # bundled Claude Agent SDK with credentials. Claude Code is the default.
10
+ # OPTIONAL: bun (bundled by npm), bash >= 4, codex/cline/aider/opencode, ollama.
11
+
12
+ _lsw_ask() {
13
+ # _lsw_ask PROMPT DEFAULT -> echoes the answer; DEFAULT when --yes or no TTY
14
+ local prompt="$1" def="$2" ans=""
15
+ if [ "$_LSW_YES" = "1" ] || [ ! -t 0 ]; then
16
+ printf '%s' "$def"
17
+ return 0
18
+ fi
19
+ printf '%s [%s]: ' "$prompt" "$def" >&2
20
+ read -r ans || ans=""
21
+ printf '%s' "${ans:-$def}"
22
+ }
23
+
24
+ _lsw_confirm() {
25
+ # _lsw_confirm PROMPT -> 0 for yes; --yes accepts, no TTY declines
26
+ local ans=""
27
+ [ "$_LSW_YES" = "1" ] && return 0
28
+ [ ! -t 0 ] && return 1
29
+ printf '%s [y/N] ' "$1" >&2
30
+ read -r ans || ans=""
31
+ case "$ans" in y|Y|yes|YES) return 0 ;; *) return 1 ;; esac
32
+ }
33
+
34
+ _lsw_fix() {
35
+ # _lsw_fix ID FALLBACK -> the one-line fix from the shared requirements table
36
+ # (autonomy/lib/setup-requirements.json), the same text loki doctor prints.
37
+ local out=""
38
+ out="$(jq -r --arg id "$1" '.requirements[] | select(.id == $id) | .fix' "${SKILL_DIR}/autonomy/lib/setup-requirements.json" 2>/dev/null | head -n 1)" || out=""
39
+ printf '%s' "${out:-$2}"
40
+ }
41
+
42
+ _lsw_tool() {
43
+ # _lsw_tool NAME LABEL INSTALL_HINT
44
+ if command -v "$1" >/dev/null 2>&1; then
45
+ printf ' [ OK ] %-10s %s\n' "$1" "$2"
46
+ return 0
47
+ fi
48
+ printf ' [MISS] %-10s %s. Install: %s\n' "$1" "$2" "$3"
49
+ [ "$2" = "REQUIRED" ] && _LSW_MISSING=$((_LSW_MISSING + 1))
50
+ return 1
51
+ }
52
+
53
+ _lsw_help() {
54
+ echo "loki setup - first-run wizard (tools, provider, model route, spend cap)"
55
+ echo ""
56
+ echo "Usage: loki setup [--yes] [--provider NAME] [--model ROUTE] [--budget USD] [--global] [--check]"
57
+ echo ""
58
+ echo " --yes, -y Non-interactive: accept defaults, never prompt"
59
+ echo " --provider NAME claude (default), codex, cline, aider, opencode"
60
+ echo " --model ROUTE claude (default), ollama/<model>, openrouter/<vendor>/<model>"
61
+ echo " --budget USD Spend cap in USD (default: none)"
62
+ echo " --global Write to ~/.config/loki-mode instead of .loki/config"
63
+ echo " --check Report only; change nothing"
64
+ echo ""
65
+ echo "Related: loki welcome (intro), loki quickstart (first build), loki doctor (health)."
66
+ }
67
+
68
+ cmd_setup() {
69
+ _LSW_YES=0
70
+ _LSW_MISSING=0
71
+ local provider="" model="" budget="" use_global="" check_only=0
72
+ while [ $# -gt 0 ]; do
73
+ case "$1" in
74
+ --yes|-y) _LSW_YES=1 ;;
75
+ --provider) provider="${2:-}"; shift ;;
76
+ --model) model="${2:-}"; shift ;;
77
+ --budget) budget="${2:-}"; shift ;;
78
+ --global) use_global="--global" ;;
79
+ --check) check_only=1 ;;
80
+ --help|-h) _lsw_help; return 0 ;;
81
+ *) echo "Unknown option: $1" >&2; _lsw_help >&2; return 2 ;;
82
+ esac
83
+ shift
84
+ done
85
+ [ -n "${CI:-}" ] && _LSW_YES=1
86
+
87
+ echo "Loki Mode setup"
88
+ echo ""
89
+ echo "1. Required tools"
90
+ _lsw_tool node REQUIRED "$(_lsw_fix node "install Node 20+ from https://nodejs.org")" || true
91
+ _lsw_tool python3 REQUIRED "$(_lsw_fix python3 "install python3")" || true
92
+ _lsw_tool jq REQUIRED "$(_lsw_fix jq "install jq")" || true
93
+ _lsw_tool git REQUIRED "$(_lsw_fix git "install git")" || true
94
+ _lsw_tool curl REQUIRED "$(_lsw_fix curl "install curl")" || true
95
+ _lsw_tool bun OPTIONAL "$(_lsw_fix bun "bundled by npm; else see https://bun.sh")" || true
96
+ if [ "$_LSW_MISSING" -gt 0 ]; then
97
+ echo ""
98
+ echo "Install the missing REQUIRED tools above with your package manager (setup never installs system packages), then rerun: loki setup"
99
+ return 1
100
+ fi
101
+
102
+ echo ""
103
+ echo "2. Provider CLI (Claude Code is the default and the only Tier-1 provider)"
104
+ local p
105
+ for p in codex cline aider opencode; do
106
+ _lsw_tool "$p" OPTIONAL "$(_lsw_fix "$p" "see 'loki doctor' for the command")" || true
107
+ done
108
+ if command -v claude >/dev/null 2>&1; then
109
+ printf ' [ OK ] %-10s DEFAULT\n' claude
110
+ if claude auth status 2>/dev/null | grep -q '"loggedIn"[[:space:]]*:[[:space:]]*true'; then
111
+ echo " claude is logged in."
112
+ else
113
+ echo " claude is installed but not logged in. Run: claude auth login"
114
+ if [ "$check_only" = 0 ] && _lsw_confirm "Run 'claude auth login' now?"; then
115
+ claude auth login || true
116
+ fi
117
+ fi
118
+ else
119
+ echo " [MISS] claude DEFAULT. Install: $(_lsw_fix claude "npm install -g @anthropic-ai/claude-code") (then: claude auth login)"
120
+ if [ "$check_only" = 0 ] && [ -f "${SKILL_DIR}/autonomy/provider-offer.sh" ]; then
121
+ if _lsw_confirm "Run that install command now?"; then
122
+ # shellcheck disable=SC1091
123
+ . "${SKILL_DIR}/autonomy/provider-offer.sh"
124
+ LOKI_ASSUME_YES="$_LSW_YES" _po_do_install || true
125
+ fi
126
+ fi
127
+ if ! command -v claude >/dev/null 2>&1; then
128
+ echo " Claude Code is not mandatory if another provider above is installed,"
129
+ echo " or if you use the Anthropic API-key path (LOKI_SDK_MODE=full with ANTHROPIC_API_KEY)."
130
+ echo " Requirements per path: loki doctor --requirements"
131
+ fi
132
+ fi
133
+
134
+ if [ "$check_only" = 1 ]; then
135
+ echo ""
136
+ echo "Check only: no config written."
137
+ return 0
138
+ fi
139
+
140
+ echo ""
141
+ echo "3. Provider and model route"
142
+ [ -z "$provider" ] && provider="$(_lsw_ask "Provider (claude|codex|cline|aider|opencode)" claude)"
143
+ [ -z "$model" ] && model="$(_lsw_ask "Model route (claude | ollama/<model> | openrouter/<vendor>/<model>)" claude)"
144
+ echo ""
145
+ echo "4. Spend cap"
146
+ [ -z "$budget" ] && budget="$(_lsw_ask "Spend cap in USD (blank for none)" "")"
147
+
148
+ echo ""
149
+ echo "5. Writing config"
150
+ # shellcheck disable=SC2086
151
+ cmd_config_set $use_global provider "$provider" || return 1
152
+ if [ -n "$budget" ]; then
153
+ # shellcheck disable=SC2086
154
+ cmd_config_set $use_global budget "$budget" || return 1
155
+ fi
156
+ case "$model" in
157
+ ""|claude) ;;
158
+ ollama/*)
159
+ echo " Model route: pass '--model $model' to loki start (Ollama must be running: ollama serve)."
160
+ ;;
161
+ openrouter/*)
162
+ echo " Model route: pass '--model $model' and export OPENROUTER_API_KEY (setup never stores keys)."
163
+ ;;
164
+ *) echo " Unrecognized route '$model'; using the provider default." ;;
165
+ esac
166
+
167
+ echo ""
168
+ echo "Done. Next: loki doctor (verify), loki quickstart (first build). Inspect: loki config list"
169
+ return 0
170
+ }
@@ -38,6 +38,8 @@
38
38
  # 1 CONCERNS
39
39
  # 2 BLOCKED
40
40
  # 3 verifier error (could not complete; never silently passes)
41
+ # 64 usage error (unknown option / unexpected argument)
42
+ # Not a git repo exits 2; an empty diff exits 3 (enforced from v11.4.0).
41
43
  #
42
44
  # EXIT-CODE ORDERING, RECONCILED. An early draft spec listed
43
45
  # 0=VERIFIED, 1=BLOCKED, 2=CONCERNS, and this header used to say a human must
@@ -66,6 +68,7 @@ VERIFY_EXIT_VERIFIED=0
66
68
  VERIFY_EXIT_CONCERNS=1
67
69
  VERIFY_EXIT_BLOCKED=2
68
70
  VERIFY_EXIT_ERROR=3
71
+ VERIFY_EXIT_USAGE=64
69
72
  VERIFY_SCHEMA_VERSION="1.0"
70
73
 
71
74
  # S-216: verify runs from the tree under review (tree="."), and a bare
@@ -355,8 +358,10 @@ verify_diff_base() {
355
358
  VERIFY_DIFF_INS=0
356
359
  VERIFY_DIFF_DEL=0
357
360
  VERIFY_DIFF_NAMES=""
361
+ VERIFY_NOT_GIT=0
358
362
 
359
363
  if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
364
+ VERIFY_NOT_GIT=1
360
365
  _verify_log "not a git repository; diff base unresolved (inconclusive)"
361
366
  return 0
362
367
  fi
@@ -2187,6 +2192,16 @@ verify_compute_verdict() {
2187
2192
  elif [ "$has_nonblock_finding" = "true" ] || [ "$inconclusive" = "true" ]; then
2188
2193
  VERIFY_VERDICT="CONCERNS"
2189
2194
  VERIFY_EXIT=$VERIFY_EXIT_CONCERNS
2195
+ # Exit contract (v11.4.0): the two inputs that give the verifier nothing
2196
+ # to check map to their own codes. The verdict word stays CONCERNS so
2197
+ # evidence.json is unchanged; only the process status is sharper.
2198
+ if [ "$has_nonblock_finding" != "true" ]; then
2199
+ if [ "${VERIFY_NOT_GIT:-0}" = "1" ]; then
2200
+ VERIFY_EXIT=$VERIFY_EXIT_BLOCKED
2201
+ elif [ "${VERIFY_DIFF_RESOLVED:-false}" = "true" ] && [ "${VERIFY_DIFF_FILES:-0}" -eq 0 ]; then
2202
+ VERIFY_EXIT=$VERIFY_EXIT_ERROR
2203
+ fi
2204
+ fi
2190
2205
  else
2191
2206
  VERIFY_VERDICT="VERIFIED"
2192
2207
  VERIFY_EXIT=$VERIFY_EXIT_VERIFIED
@@ -2253,6 +2268,7 @@ verify_emit_evidence() {
2253
2268
  _V_SCOPE_SOFT_NET="${VERIFY_SCOPE_SOFT_NET_LINES:-}" \
2254
2269
  _V_SCOPE_MAX_FILES="${VERIFY_SCOPE_MAX_FILES:-}" \
2255
2270
  _V_SCOPE_MAX_NET="${VERIFY_SCOPE_MAX_NET_LINES:-}" \
2271
+ _V_LIBDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib" \
2256
2272
  _verify_py - <<'PYEOF'
2257
2273
  import json, os, hashlib, sys
2258
2274
 
@@ -2386,6 +2402,27 @@ if _scope_verdict:
2386
2402
  "thresholds": _thresholds,
2387
2403
  }
2388
2404
 
2405
+ # Verification record (docs/PROOF-PASSPORT.md): integrity, execution
2406
+ # validity (revision + environment) and requirement coverage, kept separate, plus
2407
+ # per-check status and a scoped label. Additive; verdict/exit_code are untouched.
2408
+ # A failure to build it is recorded, never swallowed into a clean-looking doc.
2409
+ try:
2410
+ sys.path.insert(0, os.environ["_V_LIBDIR"])
2411
+ import importlib.util
2412
+ _spec = importlib.util.spec_from_file_location(
2413
+ "loki_proof_verify", os.path.join(os.environ["_V_LIBDIR"], "proof-verify.py"))
2414
+ _pv_mod = importlib.util.module_from_spec(_spec)
2415
+ _spec.loader.exec_module(_pv_mod)
2416
+ doc["verification"] = _pv_mod.build_for_evidence(
2417
+ doc, repo_dir=".", loki_dir=os.environ.get("LOKI_DIR") or ".loki",
2418
+ record_path="", fresh_capture=True)
2419
+ # base_verdict duplicates doc["verdict"]; record_path would pin the output
2420
+ # directory into a document that must be byte-identical across directories.
2421
+ doc["verification"].pop("base_verdict", None)
2422
+ except Exception as _vr_exc:
2423
+ doc["verification"] = {"schema_version": "1.0", "error": "verification record unavailable: %s" % _vr_exc,
2424
+ "label": doc["verdict"] + " (verification record unavailable)"}
2425
+
2389
2426
  os.makedirs(out_dir, exist_ok=True)
2390
2427
  ev_path = os.path.join(out_dir, "evidence.json")
2391
2428
  with open(ev_path, "w") as f:
@@ -2422,6 +2459,10 @@ lines.append("# Autonomi Verify report")
2422
2459
  lines.append("")
2423
2460
  lines.append("Verdict: **%s** (exit %d)" % (doc["verdict"], doc["exit_code"]))
2424
2461
  lines.append("")
2462
+ _vr_label = (doc.get("verification") or {}).get("label")
2463
+ if _vr_label:
2464
+ lines.append("Verification: %s" % _vr_label)
2465
+ lines.append("")
2425
2466
  _llm = doc.get("llm_review") or {}
2426
2467
  _llm_status = _llm.get("status", "unavailable")
2427
2468
  if _llm_status == "reviewed":
@@ -2570,6 +2611,11 @@ EXIT CODES:
2570
2611
  1 CONCERNS
2571
2612
  2 BLOCKED
2572
2613
  3 verifier error (could not complete; never silently passes)
2614
+ 64 usage error (unknown option or unexpected argument)
2615
+
2616
+ Two inputs that leave nothing to check have their own codes: a directory
2617
+ that is not a git repository exits 2, an empty diff vs base exits 3. The
2618
+ VERDICT line still reads CONCERNS for both.
2573
2619
 
2574
2620
  Severity rises with the code, so `[ $rc -ge 2 ]` means "at least blocked".
2575
2621
  An early draft spec listed 1=BLOCKED, 2=CONCERNS; that ordering was
@@ -3238,10 +3284,10 @@ verify_main() {
3238
3284
  --allow-unsigned) VERIFY_ALLOW_UNSIGNED=1; shift ;;
3239
3285
  --) shift; break ;;
3240
3286
  -*)
3241
- _verify_err "unknown option: $1"; verify_help; return $VERIFY_EXIT_ERROR ;;
3287
+ _verify_err "unknown option: $1"; verify_help; return $VERIFY_EXIT_USAGE ;;
3242
3288
  *)
3243
3289
  if [ -z "$base_ref" ]; then base_ref="$1"; else
3244
- _verify_err "unexpected argument: $1"; return $VERIFY_EXIT_ERROR
3290
+ _verify_err "unexpected argument: $1"; return $VERIFY_EXIT_USAGE
3245
3291
  fi
3246
3292
  shift ;;
3247
3293
  esac
@@ -3399,7 +3445,20 @@ verify_main() {
3399
3445
  # Under --json stdout carries the evidence document alone, so the human
3400
3446
  # banner is redirected to stderr rather than dropped: an operator watching a
3401
3447
  # terminal still sees the verdict, and `| jq` still parses.
3402
- printf 'VERDICT: %s\n' "$VERIFY_VERDICT" >&$_v_banner_fd
3448
+ # Scoped label + compact reviewer summary from the verification record just
3449
+ # written to evidence.json. The exit code is unchanged; only the wording is
3450
+ # stricter: a skipped or not-run check never leaves a bare "VERIFIED".
3451
+ local _v_lib _v_label _v_summary
3452
+ _v_lib="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib"
3453
+ _v_label="$VERIFY_VERDICT"
3454
+ if [ -f "$_v_lib/proof-verify.py" ]; then
3455
+ _v_summary="$(_verify_py "$_v_lib/proof-verify.py" summary "$out_dir/evidence.json" --embedded 2>/dev/null)" || _v_summary=""
3456
+ if [ -n "$_v_summary" ]; then
3457
+ _v_label="${_v_summary%%$'\n'*}"
3458
+ printf '%s\n' "${_v_summary#*$'\n'}" >&$_v_banner_fd
3459
+ fi
3460
+ fi
3461
+ printf 'VERDICT: %s\n' "$_v_label" >&$_v_banner_fd
3403
3462
  printf 'Evidence: %s/evidence.json\n' "$out_dir" >&$_v_banner_fd
3404
3463
  printf 'Report: %s/report.md\n' "$out_dir" >&$_v_banner_fd
3405
3464
  # --hosted only: surface the enrichment in human output so the extra signal
package/bin/loki CHANGED
@@ -245,6 +245,48 @@ if [ "${LOKI_PROVIDER:-}" = "gemini" ]; then
245
245
  exit 1
246
246
  fi
247
247
 
248
+ # OC-MODELS: `loki start|quick ... --model <id>` (also flag-first). One place maps the flag to
249
+ # env before ANY engine/route decision, so engine10, the Bun start command and the legacy
250
+ # loop all see the same thing. Route specs (openrouter|ollama|lmstudio|llamacpp|vllm|custom/<id>)
251
+ # set LOKI_MODEL_ROUTE (claude child only); tier names and Claude aliases become --session-model;
252
+ # any other id sets LOKI_OPENCODE_MODEL for opencode or LOKI_MODEL_OVERRIDE otherwise.
253
+ case "${1:-}" in
254
+ start|quick|--model|--model=*)
255
+ _lm_has=0
256
+ for _lm_a in "$@"; do case "$_lm_a" in --model|--model=*) _lm_has=1 ;; esac; done
257
+ if [ "$_lm_has" = "1" ]; then
258
+ _lm_out=(); _lm_model=""; _lm_prov=""; _lm_skip=0; _lm_pnext=0
259
+ for _lm_a in "$@"; do
260
+ if [ "$_lm_skip" = "1" ]; then case "$_lm_a" in -*) _lm_model=""; break ;; esac; _lm_model="$_lm_a"; _lm_skip=0; continue; fi
261
+ if [ "$_lm_pnext" = "1" ]; then _lm_prov="$_lm_a"; _lm_pnext=0; fi
262
+ case "$_lm_a" in
263
+ --model) _lm_skip=1; continue ;;
264
+ --model=*) _lm_model="${_lm_a#--model=}"; continue ;;
265
+ --provider) _lm_pnext=1 ;;
266
+ --provider=*) _lm_prov="${_lm_a#--provider=}" ;;
267
+ esac
268
+ _lm_out+=("$_lm_a")
269
+ done
270
+ if [ -n "$_lm_model" ]; then
271
+ [ -n "$_lm_prov" ] || _lm_prov="${LOKI_PROVIDER:-claude}"
272
+ case "$_lm_model" in
273
+ openrouter/*|ollama/*|lmstudio/*|llamacpp/*|vllm/*|custom/*) export LOKI_MODEL_ROUTE="$_lm_model" ;;
274
+ small|medium|high|opus|sonnet|haiku) _lm_out+=(--session-model "$_lm_model") ;;
275
+ *)
276
+ if [ "$_lm_prov" = "opencode" ]; then export LOKI_OPENCODE_MODEL="$_lm_model"
277
+ else export LOKI_MODEL_OVERRIDE="$_lm_model"; fi
278
+ ;;
279
+ esac
280
+ else
281
+ echo "loki: --model requires a value (for example ollama/qwen3-coder or openrouter/<id>)." >&2
282
+ exit 2
283
+ fi
284
+ set -- ${_lm_out[@]+"${_lm_out[@]}"}
285
+ fi
286
+ unset _lm_has _lm_out _lm_model _lm_prov _lm_skip _lm_pnext _lm_a
287
+ ;;
288
+ esac
289
+
248
290
  # First-run funnel, stage C: the activation ATTEMPT (first `loki start`).
249
291
  #
250
292
  # WHY HERE. This shim runs for BOTH routes before any exec, so one emit at this
@@ -406,29 +448,16 @@ _loki_start_needs_bash() {
406
448
  esac
407
449
  done
408
450
  unset _loki_iso_next
409
-
410
- # The Bun RARV loop has not ported the opencode invoker yet. Keep the
411
- # released, autonomous shell adapter reachable when SDK mode is enabled
412
- # instead of accepting the selection and then failing after intake. CLI
413
- # selection wins over env, which wins over the project-level saved choice.
414
- local effective_provider="$explicit_provider"
415
- if [ -z "$effective_provider" ] && [ -n "${LOKI_PROVIDER:-}" ]; then
416
- effective_provider="$LOKI_PROVIDER"
417
- fi
418
- if [ -z "$effective_provider" ] && [ -f "${PWD}/.loki/state/provider" ]; then
419
- effective_provider="$(sed -n '1p' "${PWD}/.loki/state/provider" 2>/dev/null || true)"
420
- fi
421
- [ "$effective_provider" = "opencode" ] && return 0
422
451
  return 1
423
452
  }
424
453
  _loki_attempts_refuse() {
425
454
  if _loki_start_needs_bash "$@"; then
426
- echo "loki: 'loki start --attempts' runs only the Loki 10 engine; an option or provider in this command (for example --parallel, --github, --sandbox, --issue, --dry-run, --detach, or opencode) was only honored by the removed legacy loop. Remove it, or use a task string, an issue ref or a PRD path." >&2
455
+ echo "loki: 'loki start --attempts' runs only the Loki 10 engine; an option or provider in this command (for example --parallel, --github, --sandbox, --issue, --dry-run, or --detach) was only honored by the removed legacy loop. Remove it, or use a task string, an issue ref or a PRD path." >&2
427
456
  exit 2
428
457
  fi
429
458
  case "${LOKI_PROVIDER:-claude}" in
430
- claude|codex|cline|aider) ;;
431
- *) echo "loki: the Loki 10 engine does not support LOKI_PROVIDER=${LOKI_PROVIDER:-}; use claude, codex, cline or aider." >&2; exit 2 ;;
459
+ claude|codex|cline|aider|opencode) ;;
460
+ *) echo "loki: the Loki 10 engine does not support LOKI_PROVIDER=${LOKI_PROVIDER:-}; use claude, codex, cline, aider or opencode." >&2; exit 2 ;;
432
461
  esac
433
462
  }
434
463
 
@@ -482,6 +511,28 @@ if [ "${1:-}" = "start" ]; then
482
511
  unset _loki_sp_a
483
512
  fi
484
513
 
514
+ # OC-ROUTE: normalize flags before the engine decision so argument order and input form
515
+ # never change the engine (autonomy/route.sh; `loki route ...` and --explain-route print it).
516
+ _R_APPLIED=0
517
+ if [ -f "$REPO_ROOT/autonomy/route.sh" ] && { [ "$_LOKI_START_ATTEMPTS" != "1" ] || case " $* " in *" --explain-route "*) true ;; *) false ;; esac; }; then
518
+ # shellcheck source=/dev/null
519
+ . "$REPO_ROOT/autonomy/route.sh"
520
+ _r_rc=0
521
+ loki_route_dispatch "$@" || _r_rc=$?
522
+ case "$_r_rc" in 7) exit 0 ;; 8) exit 2 ;; esac
523
+ if [ "$R_DECIDED" = "1" ]; then
524
+ _R_APPLIED=1
525
+ if [ -n "$R_SESSION_MODEL" ]; then
526
+ case "$R_SESSION_MODEL" in small) R_SESSION_MODEL=fast ;; medium) R_SESSION_MODEL=development ;; high) R_SESSION_MODEL=planning ;; esac
527
+ export LOKI_SESSION_MODEL="$R_SESSION_MODEL"
528
+ fi
529
+ if [ "$R_E10" != "1" ]; then
530
+ set -- "$([ "$R_VERB" = "bare" ] && echo start || echo "$R_VERB")" ${R_CLEAN[@]+"${R_CLEAN[@]}"}
531
+ fi
532
+ fi
533
+ unset _r_rc
534
+ fi
535
+
485
536
  # Loki 10 engine (D29, the only engine from 11.0.0). Routes `loki "<task>"`,
486
537
  # `loki owner/repo#N`, `loki quick "<task>"`, `keys` and `verify --pubkey` to engine10.
487
538
  # shellcheck disable=SC2194
@@ -566,14 +617,18 @@ case "v10" in
566
617
  # issue refs reach v10.
567
618
  *) _e10=0 ;;
568
619
  esac
620
+ if [ "$_R_APPLIED" = "1" ]; then
621
+ _e10="$R_E10"; _e10_hard="$R_HARD"
622
+ if [ "$R_E10" = "1" ]; then _e10_args=("${R_E10_ARGS[@]}"); fi
623
+ fi
569
624
  # Default (unset) mode never breaks a host: no bun, or a provider engine10 has no
570
625
  # invoker for, falls through to the legacy engine. Explicit v10 keeps its hard error.
571
626
  if [ "$_e10" = "1" ] && [ "$_e10_hard" = "0" ]; then
572
627
  case "${LOKI_PROVIDER:-claude}" in
573
- claude|codex|cline|aider) ;;
628
+ claude|codex|cline|aider|opencode) ;;
574
629
  *)
575
630
  _e10=0
576
- echo "loki: using the legacy engine (the Loki 10 engine does not support LOKI_PROVIDER=${LOKI_PROVIDER:-}; use claude, codex, cline or aider)." >&2
631
+ echo "loki: using the legacy engine (the Loki 10 engine does not support LOKI_PROVIDER=${LOKI_PROVIDER:-}; use claude, codex, cline, aider or opencode)." >&2
577
632
  ;;
578
633
  esac
579
634
  if [ "$_e10" = "1" ]; then
package/completions/_loki CHANGED
@@ -64,8 +64,52 @@ function _loki {
64
64
  doctor)
65
65
  _arguments \
66
66
  '--json[Output machine-readable JSON]' \
67
+ '--fix[Create state dirs and a default config]' \
67
68
  '--help[Show help]'
68
69
  ;;
70
+ chat)
71
+ _arguments \
72
+ '--attach[Attach to a running session]' \
73
+ '--tui[Use the terminal UI]' \
74
+ '--help[Show help]'
75
+ ;;
76
+ agents)
77
+ _arguments \
78
+ '1:subcommand:(list new show export)' \
79
+ '--claude[Export to .claude/agents]' \
80
+ '--user[Use the user-level agents directory]' \
81
+ '--help[Show help]'
82
+ ;;
83
+ models)
84
+ _arguments \
85
+ '--local[Show local models]' \
86
+ '--json[Output machine-readable JSON]' \
87
+ '--help[Show help]'
88
+ ;;
89
+ setup)
90
+ _arguments \
91
+ '--yes[Non-interactive defaults]' \
92
+ '--check[Report only]' \
93
+ '--help[Show help]'
94
+ ;;
95
+ route)
96
+ _arguments \
97
+ '1:verb:(start quick)' \
98
+ '--json[Output machine-readable JSON]' \
99
+ '--provider[AI provider]:provider name:(claude cline codex aider opencode)' \
100
+ '--model[Model or route override]:model:' \
101
+ '--no-pr[Skip the pull request]' \
102
+ '--max-cost[Spend cap in USD]:amount:' \
103
+ '--help[Show help]'
104
+ ;;
105
+ edit)
106
+ _arguments \
107
+ '--verify[Run verification after the edit]' \
108
+ '--commit[Commit the edit]' \
109
+ '--dry-run[Describe the change only]' \
110
+ '--help[Show help]' \
111
+ '*:file:_files'
112
+ ;;
69
113
  reset)
70
114
  _loki_reset
71
115
  ;;
@@ -219,6 +263,13 @@ function _loki_commands {
219
263
  'queue:Overnight issue queue with a morning digest'
220
264
  'issues:Run every open issue in a repo and open PRs'
221
265
  'undo:Show what undoing a run would do (read-only plan)'
266
+ 'chat:Interactive chat session (run, attach)'
267
+ 'route:Print the engine, provider and model route without running'
268
+ 'edit:Make a scoped edit to files'
269
+ 'setup:First-run wizard for tools, provider, model route and spend cap'
270
+ 'models:List models and routes (--local for local models)'
271
+ 'agents:List, scaffold, show and export agent definitions'
272
+ 'diff:Show what the last run changed'
222
273
  'control:Control plane (preview, LOKI_CONTROL=1)'
223
274
  'workspace:Multi-project workspaces (preview, LOKI_WORKSPACES=1)'
224
275
  'backlog:Run every matching open issue, N in parallel'
@@ -275,6 +326,10 @@ function _loki_start {
275
326
  '--yes[Skip confirmation prompts]' \
276
327
  '-y[Skip confirmation prompts]' \
277
328
  '--budget[Cost budget limit in USD]:amount:' \
329
+ '--model[Model or route override]:model:' \
330
+ '--max-cost[Spend cap in USD]:amount:' \
331
+ '--no-pr[Build and verify without opening a pull request]' \
332
+ '--explain-route[Print the route without running]' \
278
333
  '--max-iterations[Max iterations]:number:' \
279
334
  '--attempts[Independent attempts in worktrees, 1-5]:number:(1 2 3 4 5)' \
280
335
  '*:spec file:_loki_spec_files'
@@ -323,7 +378,8 @@ function _loki_provider {
323
378
  'show:Display current provider'
324
379
  'set:Set default provider'
325
380
  'list:List available providers'
326
- 'info:Get provider information'
381
+ 'info:Get provider information (--json: capability contract)'
382
+ 'matrix:Show the capability matrix'
327
383
  'help:Provider help'
328
384
  )
329
385
  _describe -t cmds 'provider subcommand' cmds
@@ -334,6 +390,7 @@ function _loki_plan {
334
390
  '--json[Machine-readable JSON output]' \
335
391
  '--verbose[Detailed per-iteration breakdown]' \
336
392
  '--spec[Write editable acceptance criteria to .loki/specs/<slug>.md]' \
393
+ '--requirements[Print the last run requirement-to-check map (read-only)]' \
337
394
  '*:prd file:_files'
338
395
  }
339
396
 
@@ -5,7 +5,7 @@ _loki_completion() {
5
5
  _init_completion || return
6
6
 
7
7
  # Main subcommands (must match autonomy/loki main case statement)
8
- local main_commands="start backlog quick monitor demo tour welcome init stop pause resume steer status next ship dashboard web serve api sandbox notify import github issue intent config provider reset memory compound checkpoint council dogfood projects enterprise secrets cockpit secure own handoff doctor watchdog audit metrics syslog onboard share proof receipt outcomes explain plan report cost estimate kpis stats test ci watch telemetry agent context ctx code run export review optimize heal modernize migrate cluster worktree wt trigger failover remote deploy docker mcp magic assets analyze compliance crash control workspace open otel preview quickstart rc rollback merge self-update sentrux setup-skill spec state template trust trust-metrics ultracode update verify voice why wiki bench cleanup logs grill docs cp version completions help keys answer queue issues undo acp verify-pr"
8
+ local main_commands="start backlog quick monitor demo tour welcome init stop pause resume steer status next ship dashboard web serve api sandbox notify import github issue intent config provider reset memory compound checkpoint council dogfood projects enterprise secrets cockpit secure own handoff doctor watchdog audit metrics syslog onboard share proof receipt outcomes explain plan report cost estimate kpis stats test ci watch telemetry agent context ctx code run export review optimize heal modernize migrate cluster worktree wt trigger failover remote deploy docker mcp magic assets analyze compliance crash control workspace open otel preview quickstart rc rollback merge self-update sentrux setup-skill spec state template trust trust-metrics ultracode update verify voice why wiki bench cleanup logs grill docs cp version completions help keys answer queue issues undo acp verify-pr chat route edit setup models agents diff"
9
9
 
10
10
  # 1. If we are on the first argument (subcommand)
11
11
  if [[ $cword -eq 1 ]]; then
@@ -27,7 +27,7 @@ _loki_completion() {
27
27
 
28
28
  # If the word starts with a dash, show flags
29
29
  if [[ "$cur" == -* ]]; then
30
- local flags="--provider --max-iterations --parallel --background --bg --simple --complex --github --no-dashboard --sandbox --skip-memory --spec --spec-first --yes --budget --attempts --help"
30
+ local flags="--provider --max-iterations --parallel --background --bg --simple --complex --github --no-dashboard --sandbox --skip-memory --spec --spec-first --yes --budget --attempts --model --isolation --max-cost --no-pr --explain-route --help"
31
31
  COMPREPLY=( $(compgen -W "${flags}" -- "$cur") )
32
32
  return 0
33
33
  fi
@@ -67,7 +67,7 @@ _loki_completion() {
67
67
  ;;
68
68
 
69
69
  provider)
70
- local provider_cmds="show set list info help"
70
+ local provider_cmds="show set list info matrix help"
71
71
  COMPREPLY=( $(compgen -W "${provider_cmds}" -- "$cur") )
72
72
  ;;
73
73
 
@@ -123,9 +123,61 @@ _loki_completion() {
123
123
  fi
124
124
  ;;
125
125
 
126
+ setup-skill)
127
+ if [[ "$cur" == -* ]]; then
128
+ COMPREPLY=( $(compgen -W "--claude-code --print --project --stop-hook --settings --help" -- "$cur") )
129
+ return 0
130
+ fi
131
+ ;;
126
132
  doctor)
127
133
  if [[ "$cur" == -* ]]; then
128
- COMPREPLY=( $(compgen -W "--json --help" -- "$cur") )
134
+ COMPREPLY=( $(compgen -W "--json --fix --repo --requirements --help" -- "$cur") )
135
+ return 0
136
+ fi
137
+ ;;
138
+
139
+ chat)
140
+ if [[ "$cur" == -* ]]; then
141
+ COMPREPLY=( $(compgen -W "--attach --tui --help" -- "$cur") )
142
+ return 0
143
+ fi
144
+ ;;
145
+
146
+ agents)
147
+ if [[ $cword -eq 2 ]]; then
148
+ COMPREPLY=( $(compgen -W "list new show export" -- "$cur") )
149
+ elif [[ "$cur" == -* ]]; then
150
+ COMPREPLY=( $(compgen -W "--claude --user --help" -- "$cur") )
151
+ fi
152
+ return 0
153
+ ;;
154
+
155
+ models)
156
+ if [[ "$cur" == -* ]]; then
157
+ COMPREPLY=( $(compgen -W "--local --json --help" -- "$cur") )
158
+ return 0
159
+ fi
160
+ ;;
161
+
162
+ setup)
163
+ if [[ "$cur" == -* ]]; then
164
+ COMPREPLY=( $(compgen -W "--yes --check --help" -- "$cur") )
165
+ return 0
166
+ fi
167
+ ;;
168
+
169
+ route)
170
+ if [[ $cword -eq 2 ]]; then
171
+ COMPREPLY=( $(compgen -W "start quick" -- "$cur") )
172
+ elif [[ "$cur" == -* ]]; then
173
+ COMPREPLY=( $(compgen -W "--json --provider --model --no-pr --max-cost --help" -- "$cur") )
174
+ fi
175
+ return 0
176
+ ;;
177
+
178
+ edit)
179
+ if [[ "$cur" == -* ]]; then
180
+ COMPREPLY=( $(compgen -W "--verify --commit --dry-run --help" -- "$cur") )
129
181
  return 0
130
182
  fi
131
183
  ;;
@@ -151,7 +203,7 @@ _loki_completion() {
151
203
 
152
204
  plan)
153
205
  if [[ "$cur" == -* ]]; then
154
- COMPREPLY=( $(compgen -W "--json --verbose --spec --help" -- "$cur") )
206
+ COMPREPLY=( $(compgen -W "--json --verbose --spec --requirements --help" -- "$cur") )
155
207
  return 0
156
208
  fi
157
209
  ;;
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "11.3.9"
10
+ __version__ = "11.5.1"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try: