loki-mode 11.3.1 → 11.3.4

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 (107) hide show
  1. package/SKILL.md +4 -4
  2. package/VERSION +1 -1
  3. package/autonomy/lib/efficiency_cost.py +8 -0
  4. package/autonomy/lib/engine10-push.sh +22 -8
  5. package/autonomy/loki +69 -30
  6. package/bin/loki +30 -1
  7. package/completions/_loki +22 -0
  8. package/completions/loki.bash +17 -3
  9. package/dashboard/__init__.py +1 -1
  10. package/dashboard/server.py +22 -14
  11. package/docs/AGENT-CHANGE-RECEIPT.md +2 -2
  12. package/docs/CLI-REFERENCE.md +5 -1
  13. package/docs/INSTALLATION.md +1 -1
  14. package/docs/OTEL-COLLECTOR.md +24 -0
  15. package/docs/ROUTING-EVIDENCE.md +32 -0
  16. package/docs/environment-variables.md +1 -0
  17. package/docs/spec-first-intent.md +28 -0
  18. package/docs/v10/CLI-MODERN.md +6 -3
  19. package/docs/v10/DECISIONS.md +20 -0
  20. package/docs/v10/FAILURE-CLASSES.md +263 -1
  21. package/docs/v10/GUARDS.md +18 -0
  22. package/docs/v10/GUIDE.md +7 -5
  23. package/docs/v10/METRICS.md +12 -0
  24. package/docs/v10/OPERATING-MODEL.md +3 -3
  25. package/docs/v10/PROGRESS.md +12 -0
  26. package/docs/v11/INTOTO-AGENT-CHANGE-PREDICATE.md +77 -0
  27. package/docs/v11/MCP-2026-07-28.md +55 -0
  28. package/docs/v11/VERIFY-PR-SANDBOX.md +41 -0
  29. package/loki-ts/dist/loki.js +1130 -969
  30. package/mcp/__init__.py +1 -1
  31. package/mcp/v10_tools.py +29 -0
  32. package/package.json +9 -11
  33. package/packages/control-plane/dist/ask-tools-server.js +8 -2
  34. package/packages/control-plane/dist/server.js +15752 -13978
  35. package/packages/control-plane/drizzle/0006_token_sessions.sql +1 -0
  36. package/packages/control-plane/drizzle/meta/0006_snapshot.json +807 -0
  37. package/packages/control-plane/drizzle/meta/_journal.json +7 -0
  38. package/packages/control-plane/src/db/schema.ts +1 -0
  39. package/packages/control-plane/src/server/routes/cost.ts +4 -3
  40. package/packages/control-plane/src/server/runs.ts +3 -3
  41. package/packages/control-plane/ui/dist/assets/index-DbLzr87u.js +190 -0
  42. package/packages/control-plane/ui/dist/index.html +1 -1
  43. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  44. package/providers/opencode.sh +2 -3
  45. package/src/observability/genai-spans.js +104 -0
  46. package/src/observability/otel-bridge.js +49 -1
  47. package/src/observability/otel.js +2 -2
  48. package/src/protocols/mcp-server.js +180 -5
  49. package/src/protocols/transport/sse.js +23 -2
  50. package/web-app/dist/assets/{AdminPage-CMkHNJbF.js → AdminPage-CKj0pDt0.js} +1 -1
  51. package/web-app/dist/assets/{Avatar-BJyjV7Zi.js → Avatar-BOV__pMM.js} +1 -1
  52. package/web-app/dist/assets/{Badge-D572l0uq.js → Badge-4a6mAYjU.js} +1 -1
  53. package/web-app/dist/assets/{Button-T4BnOZgl.js → Button-B3GM7oxm.js} +1 -1
  54. package/web-app/dist/assets/{CockpitPage-Cj_GFsNn.js → CockpitPage-Cwge3_kH.js} +1 -1
  55. package/web-app/dist/assets/{ComparePage-A8m4ZXak.js → ComparePage-CBQUGKsm.js} +1 -1
  56. package/web-app/dist/assets/{ErrorBoundary-hugCg5yg.js → ErrorBoundary-TM7lDjUJ.js} +1 -1
  57. package/web-app/dist/assets/{EvidenceReceiptPanel-CuJKDC2G.js → EvidenceReceiptPanel-DUOseTYA.js} +1 -1
  58. package/web-app/dist/assets/{GitHubIssuesPanel-BYGKjarC.js → GitHubIssuesPanel-hK_uML6T.js} +1 -1
  59. package/web-app/dist/assets/{GitHubPRsPanel-c7sFIJlf.js → GitHubPRsPanel-Bt0mug-u.js} +1 -1
  60. package/web-app/dist/assets/{HomePage-A1MIkG2P.js → HomePage-DcOogAai.js} +2 -2
  61. package/web-app/dist/assets/{LoginPage-8KQMRhtR.js → LoginPage-D41pjjhF.js} +1 -1
  62. package/web-app/dist/assets/{MagicPage-C05QW2Lx.js → MagicPage-iDcdAcL2.js} +1 -1
  63. package/web-app/dist/assets/{MetricsPage-Oukv5hme.js → MetricsPage-Tt4sfFD1.js} +1 -1
  64. package/web-app/dist/assets/{NotFoundPage-DKIwsawz.js → NotFoundPage-DPQMausn.js} +1 -1
  65. package/web-app/dist/assets/{ProjectPage-DwFRPLCG.js → ProjectPage-DdMz4frY.js} +3 -3
  66. package/web-app/dist/assets/{ProjectsPage-CgY4YYDX.js → ProjectsPage-Be0v4ace.js} +1 -1
  67. package/web-app/dist/assets/{SettingsPage-BpfcSjUA.js → SettingsPage-90yIh-mE.js} +1 -1
  68. package/web-app/dist/assets/{ShowcasePage-BqBakC4K.js → ShowcasePage-D5x5eczl.js} +1 -1
  69. package/web-app/dist/assets/{SystemSettingsPage-CZLu5VB0.js → SystemSettingsPage-UWeWT8KX.js} +1 -1
  70. package/web-app/dist/assets/{TeamsPage-D55S1jKz.js → TeamsPage-BtofFlme.js} +1 -1
  71. package/web-app/dist/assets/{TemplatesPage-D3SydvxN.js → TemplatesPage-DwB8Va2Z.js} +1 -1
  72. package/web-app/dist/assets/{TerminalOutput-hNg8G1-e.js → TerminalOutput-CGIgTmby.js} +1 -1
  73. package/web-app/dist/assets/{activity-D2C0VagO.js → activity-BZ77CO72.js} +1 -1
  74. package/web-app/dist/assets/{bell-CMvYi36w.js → bell-Bzpqv6un.js} +1 -1
  75. package/web-app/dist/assets/{bot-BvtQ6lmo.js → bot-yXo1B_-f.js} +1 -1
  76. package/web-app/dist/assets/{check-B13xkXed.js → check-BSxGjsta.js} +1 -1
  77. package/web-app/dist/assets/{chevron-left-emu6r49E.js → chevron-left-CqTRVUB5.js} +1 -1
  78. package/web-app/dist/assets/{circle-alert-CExlwjuy.js → circle-alert-88gdjY71.js} +1 -1
  79. package/web-app/dist/assets/{clock-D7Uas3oL.js → clock-XdFXoaJi.js} +1 -1
  80. package/web-app/dist/assets/{cloud-CkB4S86C.js → cloud-Tx1sJrXz.js} +1 -1
  81. package/web-app/dist/assets/{code-xml-SL9IIWIn.js → code-xml-DaH9CKWy.js} +1 -1
  82. package/web-app/dist/assets/{database-BQFkd7t1.js → database-BpvOmzij.js} +1 -1
  83. package/web-app/dist/assets/{dollar-sign-qHmnNYsU.js → dollar-sign-VC2UX2UE.js} +1 -1
  84. package/web-app/dist/assets/{file-code-corner-C2YUDP0K.js → file-code-corner--TF3VpoT.js} +1 -1
  85. package/web-app/dist/assets/{file-plus-C_ooIkDe.js → file-plus-DZpwU9pY.js} +1 -1
  86. package/web-app/dist/assets/{globe-CQ-GL485.js → globe-tbpeHRPV.js} +1 -1
  87. package/web-app/dist/assets/{hammer-U05L_D7V.js → hammer-CKLXn4vL.js} +1 -1
  88. package/web-app/dist/assets/{index-CooHd7I-.js → index-DnCsWpCh.js} +3 -3
  89. package/web-app/dist/assets/{layers-Buo17rjW.js → layers-B0fkGsk8.js} +1 -1
  90. package/web-app/dist/assets/{loader-circle-15vK3oV1.js → loader-circle-czscMzmQ.js} +1 -1
  91. package/web-app/dist/assets/{lock-BeXLebuJ.js → lock-CTtO6vc8.js} +1 -1
  92. package/web-app/dist/assets/{package-MVh_6-6R.js → package-DZeSY0-g.js} +1 -1
  93. package/web-app/dist/assets/{plus-Dh_nd9vS.js → plus-mE12CJVN.js} +1 -1
  94. package/web-app/dist/assets/{refresh-cw-C9cBJEAT.js → refresh-cw-9DSznasU.js} +1 -1
  95. package/web-app/dist/assets/{rotate-ccw-D3PAtzST.js → rotate-ccw-DcHI0M43.js} +1 -1
  96. package/web-app/dist/assets/{scroll-text-DZCoXQjo.js → scroll-text-BWLthSw-.js} +1 -1
  97. package/web-app/dist/assets/{server-OCOLI5J_.js → server-_I247LrS.js} +1 -1
  98. package/web-app/dist/assets/{shield-alert-oVhmf1_h.js → shield-alert-XRJYD_6c.js} +1 -1
  99. package/web-app/dist/assets/{thumbs-up-B-kbX4vN.js → thumbs-up-CxuTD3eO.js} +1 -1
  100. package/web-app/dist/assets/{trash-2-EL6moveW.js → trash-2-DuGxuVt8.js} +1 -1
  101. package/web-app/dist/assets/{trending-down-Cl3kjpsx.js → trending-down-Cg_zGt__.js} +1 -1
  102. package/web-app/dist/assets/{trending-up-DST7I6M2.js → trending-up-DpUJzIrV.js} +1 -1
  103. package/web-app/dist/assets/{upload-CUOT780G.js → upload-Db7YZ4zR.js} +1 -1
  104. package/web-app/dist/assets/{usePolling-Djmt90eb.js → usePolling-BGRYm-vq.js} +1 -1
  105. package/web-app/dist/assets/{user-BRBohA6J.js → user-CxHrowEP.js} +1 -1
  106. package/web-app/dist/index.html +1 -1
  107. package/packages/control-plane/ui/dist/assets/index-DcBJXjCJ.js +0 -190
package/SKILL.md CHANGED
@@ -3,9 +3,9 @@ name: loki-mode
3
3
  description: An autonomous software factory that knows what it is supposed to deliver, and proves it did. Use when the user says Loki Mode or asks to build, fix or verify software autonomously.
4
4
  ---
5
5
 
6
- # Loki Mode v11.3.1
6
+ # Loki Mode v11.3.4
7
7
 
8
- **Current entry points (Loki 10 engine):** `loki "<task>"`, `loki owner/repo#N` and `loki quick "<task>"` run the Loki 10 engine and end with a signed receipt (`loki verify`). `loki backlog owner/repo --all` runs many issues in parallel. Guide: `docs/v10/GUIDE.md`. The skill instructions below, and `loki start`, describe the legacy engine, which still ships and is being removed (`loki start owner/repo#N` still routes to it; prefer `loki owner/repo#N`).
8
+ **Current entry points (Loki 10 engine):** `loki "<task>"`, `loki owner/repo#N` and `loki quick "<task>"` run the Loki 10 engine and end with a signed receipt (`loki verify`). `loki backlog owner/repo --all` runs many issues in parallel. Guide: `docs/v10/GUIDE.md`. The skill instructions below, and `loki start`, describe the previous bash loop. PRD-file starts (`loki start ./prd.md`) and the opencode provider still run on it until FC38-SWEEP ports them; the legacy-engine command and the LOKI_ENGINE switch remain removed. Prefer `loki owner/repo#N` for issues.
9
9
 
10
10
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
11
11
 
@@ -200,7 +200,7 @@ This protocol governs **skill module** loading -- task-scoped instruction files
200
200
  <!-- generated:commands -->
201
201
  Commands (generated from `loki-ts/src/cli/registry.ts`; full reference in `docs/CLI-REFERENCE.md`):
202
202
 
203
- `version`, `status`, `doctor`, `provider`, `memory`, `rollback`, `proof`, `wiki`, `control`, `kpis`, `report`, `trust`, `crash`, `contract`, `start`, `slack`, `queue`, `answer`, `engine10`, `help`, `quick`, `quickstart`, `init`, `template`, `verify`, `keys`, `review`, `dashboard`, `config`, `mcp`, `acp`, `stop`, `pause`, `resume`, `why`, `next`, `logs`, `ship`, `deploy`, `import`, `github`, `issue`, `ci`, `modernize`, `share`, `assets`, `export`, `notify`, `tour`, `welcome`, `onboard`, `setup-skill`, `self-update`, `remote`, `cockpit`, `code`, `context`, `secrets`, `api`, `sandbox`, `docker`, `web`, `preview`, `telemetry`, `syslog`, `explain`, `docs`, `test`, `bench`, `voice`, `own`, `secure`, `compliance`, `enterprise`, `projects`, `audit`, `cost`, `metrics`, `sentrux`, `magic`
203
+ `version`, `status`, `doctor`, `provider`, `memory`, `rollback`, `proof`, `wiki`, `control`, `kpis`, `report`, `trust`, `crash`, `contract`, `start`, `slack`, `queue`, `issues`, `undo`, `verify-pr`, `answer`, `engine10`, `help`, `quick`, `quickstart`, `init`, `template`, `verify`, `keys`, `review`, `dashboard`, `config`, `mcp`, `acp`, `stop`, `pause`, `resume`, `why`, `next`, `logs`, `ship`, `deploy`, `import`, `github`, `issue`, `ci`, `modernize`, `share`, `assets`, `export`, `notify`, `tour`, `welcome`, `onboard`, `setup-skill`, `self-update`, `remote`, `cockpit`, `code`, `context`, `secrets`, `api`, `sandbox`, `docker`, `web`, `preview`, `telemetry`, `syslog`, `explain`, `docs`, `test`, `bench`, `voice`, `own`, `secure`, `compliance`, `enterprise`, `projects`, `audit`, `cost`, `metrics`, `sentrux`, `magic`
204
204
  <!-- /generated -->
205
205
 
206
206
  ---
@@ -483,4 +483,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
483
483
 
484
484
  ---
485
485
 
486
- **v11.3.1 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
486
+ **v11.3.4 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 11.3.1
1
+ 11.3.4
@@ -192,6 +192,9 @@ def collect_efficiency(loki_dir):
192
192
  # real observation, and nulling it would be its own dishonesty (existing
193
193
  # contract: test_genuine_zero_cost_stays_zero_not_null). What is unknown is a
194
194
  # record that never carried the field at all.
195
+ # FC-44: a record flagged tokens_measured:false (an ambiguous resumed session) carries no usage keys. One of them makes every
196
+ # token total NOT RECORDED (None); the flag keys are added only then, so a complete run's dict is unchanged.
197
+ _unmeasured_tokens = sum(1 for r in _records if r.get("tokens_measured") is False)
195
198
  _any_cost = any("cost_usd" in r for r in _records)
196
199
  _missing_cost = sum(1 for r in _records if "cost_usd" not in r)
197
200
  if collected and _observed:
@@ -208,6 +211,11 @@ def collect_efficiency(loki_dir):
208
211
  # Some records priced, others not: the total is a LOWER BOUND.
209
212
  cost["cost_partial"] = _missing_cost > 0
210
213
  cost["cost_unpriced_records"] = _missing_cost
214
+ if _unmeasured_tokens:
215
+ for key in ("input_tokens", "output_tokens", "cache_read_tokens", "cache_creation_tokens"):
216
+ cost[key] = None
217
+ cost["tokens_partial"] = True
218
+ cost["tokens_unmeasured_records"] = _unmeasured_tokens
211
219
  else:
212
220
  # No record means unavailable, never an observed zero.
213
221
  for key in (
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env bash
2
2
  # Loki 10 engine P4 push child (ENGINE.md sections 6 and 7).
3
3
  #
4
- # engine10-push.sh push-pr <repo-dir> <branch> <title> <body-file> [--draft]
4
+ # engine10-push.sh push-pr <repo-dir> <branch> <title> <body-file> [--draft] [--base <branch>]
5
+ # engine10-push.sh check-origin (exit 0 when the pinned origin is acceptable to push-pr, else the refusal; no network)
5
6
  # engine10-push.sh comment <pr-number> <body-file>
6
7
  # engine10-push.sh issue-comment <issue-ref> <body-file>
7
8
  # engine10-push.sh status <sha> <pending|success|failure|error> <description>
@@ -111,13 +112,26 @@ _e10_gh() { _loki_with_github_tokens _loki_run_neutral "$_e10_repo" command gh "
111
112
  mode="${1:-}"
112
113
  shift || true
113
114
  case "$mode" in
115
+ check-origin)
116
+ # The origin validation above already ran and died on a refusal; reaching here means push-pr would accept it.
117
+ exit 0
118
+ ;;
114
119
  push-pr)
115
- [ "$#" -ge 4 ] && [ "$#" -le 5 ] || die "usage: push-pr <repo-dir> <branch> <title> <body-file> [--draft]"
116
- dir="$1" branch="$2" title="$3" body="$4" draft=()
117
- if [ "$#" -eq 5 ]; then
118
- [ "$5" = "--draft" ] || die "unknown flag: $5"
119
- draft=(--draft)
120
- fi
120
+ [ "$#" -ge 4 ] && [ "$#" -le 7 ] || die "usage: push-pr <repo-dir> <branch> <title> <body-file> [--draft] [--base <branch>]"
121
+ dir="$1" branch="$2" title="$3" body="$4" draft=() base=()
122
+ shift 4
123
+ # MASS-2: --base stacks the PR on a parent slice's branch; a name git would not accept is refused.
124
+ while [ "$#" -gt 0 ]; do
125
+ case "$1" in
126
+ --draft) draft=(--draft); shift ;;
127
+ --base)
128
+ [ "$#" -ge 2 ] || die "--base needs a branch"
129
+ case "$2" in -* | '') die "invalid base branch: $2" ;; esac
130
+ git check-ref-format --branch "$2" >/dev/null 2>&1 || die "invalid base branch: $2"
131
+ base=(--base "$2"); shift 2 ;;
132
+ *) die "unknown flag: $1" ;;
133
+ esac
134
+ done
121
135
  [ -f "$body" ] || die "body file not found: $body"
122
136
  if [ -n "$_e10_local" ]; then
123
137
  _e10_local_push "$dir" "$branch" || die "push refused or failed (rc=$?)"
@@ -128,7 +142,7 @@ case "$mode" in
128
142
  url="$(_e10_gh pr list --repo "$_e10_repo" --head "$branch" --state open --json url --jq '.[0].url')" \
129
143
  || die "gh pr list failed"
130
144
  if [ -z "$url" ] || [ "$url" = "null" ]; then
131
- url="$(_e10_gh pr create --repo "$_e10_repo" --head "$branch" --title "$title" --body-file "$body" "${draft[@]}")" \
145
+ url="$(_e10_gh pr create --repo "$_e10_repo" --head "$branch" --title "$title" --body-file "$body" "${draft[@]}" "${base[@]}")" \
132
146
  || die "gh pr create failed"
133
147
  url="$(printf '%s\n' "$url" | tail -n 1)"
134
148
  fi
package/autonomy/loki CHANGED
@@ -1691,6 +1691,22 @@ _help_answer() {
1691
1691
  echo "and sets LOKI_NO_BROWSER=1."
1692
1692
  }
1693
1693
 
1694
+ # `loki help verify-pr`: a Bun-only command (loki-ts), so its help lives here.
1695
+ _help_verify_pr() {
1696
+ echo -e "${BOLD}loki verify-pr${NC} - Verify a PR against its linked issue (experimental, LOKI_VERIFY_PR=1)"
1697
+ echo ""
1698
+ echo "Usage: loki verify-pr <https://github.com/o/r/pull/N | o/r#N> [--out DIR]"
1699
+ echo ""
1700
+ echo "Derives a check from the PR's linked issue (Check: \`cmd\` or a loki-check fence)."
1701
+ echo "VERIFIED only if the check fails on the PR base, passes on its head, and the"
1702
+ echo "touched packages' suites pass. A PR with no linked issue, no check, a removed"
1703
+ echo "test or a non-discriminating check is NOT PROVEN. Writes verify-pr-result.json."
1704
+ echo "PR code runs only in the container sandbox (scripts/verify-pr-sandbox.sh); set"
1705
+ echo "LOKI_VPR_IMAGE to a locally present image."
1706
+ echo ""
1707
+ echo "Exit codes: 0 verified, 2 usage or sandbox blocked, 4 not proven."
1708
+ }
1709
+
1694
1710
  # Appended to `loki help verify`: the v10 DSSE export flag (docs/exit-codes.md).
1695
1711
  _help_verify_dsse() {
1696
1712
  echo ""
@@ -1763,6 +1779,7 @@ show_help() {
1763
1779
  echo " review [opts] Standalone code review with quality gates"
1764
1780
  echo " ultracode \"task\" Run a task as a native Claude Code Dynamic Workflow (opt-in, Claude-only)"
1765
1781
  echo " trust [cmd] Visible trust trajectory; 'trust detail' for metrics"
1782
+ echo " undo <run> [--plan] Plan or apply (LOKI_UNDO=1) an undo of a run; verifies the receipt"
1766
1783
  echo ""
1767
1784
  echo "Observe:"
1768
1785
  echo " dashboard [cmd] Operations UI server (start|stop|status|url|open)"
@@ -1798,15 +1815,12 @@ show_help() {
1798
1815
  echo ""
1799
1816
  echo "Options for 'start':"
1800
1817
  echo " --provider NAME AI provider: claude (default), codex, cline, aider, opencode"
1801
- echo " --parallel Enable parallel mode with git worktrees"
1802
- echo " --bg, --background Run in background mode"
1803
1818
  echo " --simple Force simple complexity tier (3 phases)"
1804
1819
  echo " --complex Force complex complexity tier (8 phases)"
1805
- echo " --github Enable GitHub issue import"
1806
1820
  echo " --no-dashboard Disable web dashboard"
1807
- echo " --sandbox Run in Docker sandbox for isolation (default: off; requires Docker)"
1808
1821
  echo " --isolation LVL Per-run isolation dial: none (default) | worktree | docker"
1809
1822
  echo " --skip-memory Skip loading memory context at startup"
1823
+ echo " --spec FILE Run against an edited spec (written by 'loki plan <task> --spec'; see also --spec-first)"
1810
1824
  echo " --fresh-prd Regenerate the PRD from the codebase (no-PRD runs; ignores the reusable generated PRD)"
1811
1825
  echo " --compliance PRESET Enable compliance mode (default|healthcare|fintech|government)"
1812
1826
  echo " --budget USD Set cost budget limit (display in dashboard/status)"
@@ -1824,8 +1838,6 @@ show_help() {
1824
1838
  echo " loki start ./prd.md # Start with PRD file"
1825
1839
  echo " loki start owner/repo#123 # GitHub issue (auto-fetches)"
1826
1840
  echo " loki start PROJ-456 # Jira issue"
1827
- echo " loki start --bg ./prd.md # Start in background"
1828
- echo " loki start --parallel ./prd.md # Parallel mode (git worktrees)"
1829
1841
  echo " loki quick \"add dark mode\" # Single-task mode (Loki 10 engine)"
1830
1842
  echo " loki tour # See a real sample result (no provider, no key, no spend)"
1831
1843
  echo " loki demo # Build a sample todo app end to end"
@@ -1898,7 +1910,7 @@ show_help() {
1898
1910
  echo " merge resume review rollback run sandbox secrets secure self-update sentrux"
1899
1911
  echo " serve setup-skill share ship spec start state stats status steer stop"
1900
1912
  echo " syslog telemetry template test tour trigger trust trust-metrics"
1901
- echo " ultracode update verify version voice watch watchdog web welcome why"
1913
+ echo " ultracode undo update verify version voice watch watchdog web welcome why"
1902
1914
  echo " wiki workspace worktree (wt)"
1903
1915
  echo " control"
1904
1916
  echo ""
@@ -2563,20 +2575,18 @@ cmd_start() {
2563
2575
  echo " Token from LOKI_REMOTE_TOKEN / LOKI_REMOTE_TOKEN_FILE"
2564
2576
  echo " (never an argument). Env: LOKI_REMOTE_URL."
2565
2577
  echo " --provider NAME AI provider: claude (default), codex, cline, aider, opencode"
2566
- echo " --parallel Enable parallel mode with git worktrees"
2567
2578
  echo " --allow-haiku Enable Haiku model for the fast tier (default: disabled)"
2568
- echo " --bg, --background Run in background mode"
2569
2579
  echo " --simple Force simple complexity tier (3 phases)"
2570
2580
  echo " --complex Force complex complexity tier (8 phases)"
2571
- echo " --github Enable GitHub issue import"
2572
2581
  echo " --no-dashboard Disable web dashboard"
2573
2582
  echo " --api Start dashboard API server alongside the build"
2574
- echo " --sandbox Run in Docker sandbox (default: off; requires Docker)"
2575
2583
  echo " --isolation LEVEL Per-run isolation: none (default) | worktree | docker."
2576
- echo " Unified dial; --parallel = worktree, --sandbox = docker."
2584
+ echo " Unified dial."
2577
2585
  echo " --attempts N Run N (1-5, default 1) independent attempts in separate git worktrees;"
2578
2586
  echo " the most executed passing checks wins, losers are recorded on the receipt"
2579
2587
  echo " --skip-memory Skip loading memory context at startup"
2588
+ echo " --spec FILE Run against an edited .loki/specs/<slug>.md (from 'loki plan <task> --spec')"
2589
+ echo " --spec-first Write .loki/specs/<slug>.md for you to edit, then stop"
2580
2590
  echo " --fresh-prd Regenerate the PRD from the codebase on a no-PRD run"
2581
2591
  echo " (ignores the reusable generated PRD; aliases: --regen-prd,"
2582
2592
  echo " --regenerate-prd, --regen, or LOKI_PRD_REGEN=1)"
@@ -2608,7 +2618,6 @@ cmd_start() {
2608
2618
  echo " --worktree, -w Git worktree isolation (separate branch)"
2609
2619
  echo " --pr Worktree + auto-create PR"
2610
2620
  echo " --ship Worktree + PR + auto-merge"
2611
- echo " --detach, -d Run in background"
2612
2621
  echo ""
2613
2622
  echo "Preview without spending (any input mode):"
2614
2623
  echo " loki plan <PRD> Analyze a spec WITHOUT executing: complexity,"
@@ -2637,7 +2646,6 @@ cmd_start() {
2637
2646
  echo " loki start 123 # ISSUE mode (current repo GitHub issue)"
2638
2647
  echo " loki start PROJ-456 # ISSUE mode (Jira)"
2639
2648
  echo " loki start owner/repo#789 # ISSUE mode (GitHub specific repo)"
2640
- echo " loki start --prd ./prd.md --parallel # Explicit PRD, parallel mode"
2641
2649
  echo " loki start --issue 123 --ship # Explicit issue, full automation"
2642
2650
  echo " loki start --provider codex # Use OpenAI Codex CLI"
2643
2651
  echo " loki start --bmad-project ./my-project # Start from BMAD artifacts"
@@ -6424,22 +6432,35 @@ except Exception:
6424
6432
  fi
6425
6433
  fi
6426
6434
 
6427
- # v7.82: completion-aware one-liner. When a finished run left a completion
6428
- # record, show its outcome and point at \`loki why\` for the full story. Reads
6429
- # the persisted completion.json (no recompute); silent when absent.
6430
- if [ -f "$LOKI_DIR/state/completion.json" ]; then
6431
- local last_outcome
6432
- last_outcome=$(_LOKI_CJ="$LOKI_DIR/state/completion.json" python3 -c "
6433
- import json, os
6435
+ # 133-F4: newest sealed receipt's verdict, read from the receipt field only
6436
+ # (never recomputed). Missing, empty or unparseable receipts never read as
6437
+ # VERIFIED. This replaces the old completion.json one-liner (Bun never had it).
6438
+ local receipt_line
6439
+ receipt_line=$(_LOKI_RUNS="$LOKI_DIR/runs" python3 -c "
6440
+ import json, os, re
6441
+ runs = os.environ['_LOKI_RUNS']
6434
6442
  try:
6435
- d = json.load(open(os.environ['_LOKI_CJ']))
6436
- print(d.get('outcome', '') or '')
6443
+ ids = sorted(d for d in os.listdir(runs) if os.path.isdir(os.path.join(runs, d)))
6437
6444
  except Exception:
6438
- print('')" 2>/dev/null)
6439
- if [ -n "$last_outcome" ]; then
6440
- echo -e "${DIM}Last run: ${last_outcome} - run 'loki why' for details${NC}"
6441
- fi
6442
- fi
6445
+ ids = []
6446
+ if not ids:
6447
+ print('Last run: no receipt (verdict NOT AVAILABLE)')
6448
+ else:
6449
+ try:
6450
+ d = json.load(open(os.path.join(runs, ids[-1], 'receipt.json')))
6451
+ v = d['verdict']
6452
+ h = d['receipt_sha256']
6453
+ if not (isinstance(v, str) and re.fullmatch(r'[A-Z_]+', v) and isinstance(h, str)):
6454
+ raise ValueError
6455
+ h = h[7:] if h.startswith('sha256:') else h
6456
+ if not re.fullmatch(r'[0-9a-f]{12,}', h):
6457
+ raise ValueError
6458
+ print('Last run: %s (receipt sha256:%s)' % (v, h[:12]))
6459
+ except Exception:
6460
+ print('Last run: receipt unreadable')
6461
+ " 2>/dev/null)
6462
+ [ -n "$receipt_line" ] || receipt_line="Last run: receipt unreadable"
6463
+ echo -e "${DIM}${receipt_line}${NC}"
6443
6464
 
6444
6465
  echo ""
6445
6466
  echo -e "${DIM} Tip: loki analyze context show - detailed token breakdown${NC}"
@@ -12394,6 +12415,9 @@ cmd_export() {
12394
12415
  echo " csv Task queue as CSV"
12395
12416
  echo " timeline Iteration timeline as JSON"
12396
12417
  echo ""
12418
+ echo "Flags:"
12419
+ echo " --sarif [run-id] Write .loki/runs/<id>/findings.sarif (SARIF 2.1.0; needs bun)"
12420
+ echo ""
12397
12421
  echo "Examples:"
12398
12422
  echo " loki export json # Print to stdout"
12399
12423
  echo " loki export json session-export.json # Save to file"
@@ -12416,6 +12440,10 @@ cmd_export() {
12416
12440
  require_jq || return 1
12417
12441
  _export_timeline "$output_path"
12418
12442
  ;;
12443
+ --sarif)
12444
+ echo -e "${RED}loki export --sarif needs bun (https://bun.sh).${NC}" >&2
12445
+ return 1
12446
+ ;;
12419
12447
  *)
12420
12448
  echo -e "${RED}Unknown format: $format${NC}"
12421
12449
  echo "Supported: json, markdown, csv, timeline"
@@ -20666,6 +20694,7 @@ cmd_plan() {
20666
20694
  echo ""
20667
20695
  echo "Options:"
20668
20696
  echo " --json Machine-readable JSON output"
20697
+ echo " --spec With a task: write the acceptance criteria to .loki/specs/<slug>.md for you to edit"
20669
20698
  echo " --verbose Show detailed per-iteration breakdown"
20670
20699
  echo " --help, -h Show this help"
20671
20700
  echo ""
@@ -21201,6 +21230,11 @@ main() {
21201
21230
  mcp)
21202
21231
  cmd_mcp "$@"
21203
21232
  ;;
21233
+ undo)
21234
+ # UNDO-1: Bun-only (verifies the receipt with the Bun verifier); bin/loki routes here only when bun is absent.
21235
+ echo "loki undo needs the Bun runtime (install bun, then re-run: loki undo <run-id> --plan)" >&2
21236
+ exit 2
21237
+ ;;
21204
21238
  acp)
21205
21239
  # ACP agent over stdio; stdout is protocol-only. See docs/acp-editors.md.
21206
21240
  LOKI_ACP_LOKI="${LOKI_ACP_LOKI:-$_LOKI_SCRIPT_DIR/loki}" exec python3 "$_LOKI_SCRIPT_DIR/acp-agent.py"
@@ -21413,6 +21447,8 @@ main() {
21413
21447
  show_help
21414
21448
  elif [ "$_help_target" = "answer" ]; then
21415
21449
  _help_answer
21450
+ elif [ "$_help_target" = "verify-pr" ]; then
21451
+ _help_verify_pr
21416
21452
  else
21417
21453
  LOKI_HELP_ONLY=1 "$0" "$_help_target" --help "$@"
21418
21454
  local _help_rc=$?
@@ -24366,6 +24402,9 @@ except Exception as e:
24366
24402
  echo " dedupe Remove duplicate entries"
24367
24403
  echo " clear [type] Clear learnings (all or specific type)"
24368
24404
  echo " compound [cmd] Compound-solutions knowledge store (was: loki compound)"
24405
+ echo " lessons [--json] PR review lessons with their uses and outcomes"
24406
+ echo " learn <o/r#PR> Learn lessons from a merged PR's review comments"
24407
+ echo " forget <prl-id> Delete one PR lesson and print its text"
24369
24408
  echo ""
24370
24409
  echo "Memory System Commands:"
24371
24410
  echo " index [rebuild] Show or rebuild the memory index layer"
@@ -30164,7 +30203,7 @@ except: pass
30164
30203
 
30165
30204
  # Detect shell scripts
30166
30205
  local shell_count=0
30167
- shell_count=$(find "$target_path" -maxdepth 2 -name "*.sh" -type f 2>/dev/null | wc -l | tr -d ' ')
30206
+ shell_count=$(find "$target_path" -maxdepth 2 -name "*.sh" -type f 2>/dev/null | wc -l | tr -d ' ' || true)
30168
30207
  if [ "$shell_count" -gt 0 ]; then
30169
30208
  languages="$languages Bash"
30170
30209
  fi
@@ -30602,7 +30641,7 @@ Files: $src_count source, $test_count test, $doc_count docs"
30602
30641
  if [ -d "$target_path/$dir" ]; then
30603
30642
  # Count files in directory
30604
30643
  local dir_count
30605
- dir_count=$(echo "$tree_output" | grep "^${dir}/" | wc -l | tr -d ' ')
30644
+ dir_count=$(echo "$tree_output" | grep "^${dir}/" | wc -l | tr -d ' ' || true)
30606
30645
  output="$output
30607
30646
  $dir/ ($dir_count files)"
30608
30647
  else
package/bin/loki CHANGED
@@ -467,6 +467,21 @@ if [ "${1:-}" = "start" ]; then
467
467
  unset _loki_att_args _loki_att_n _loki_att_skip _loki_att_a
468
468
  fi
469
469
 
470
+ # SPEC-FIRST-INTENT: `start --spec FILE` and `start --spec-first` are parsed by the Bun start command,
471
+ # which forwards them to engine10; they never reach the positional-task route or the legacy loop.
472
+ if [ "${1:-}" = "start" ]; then
473
+ for _loki_sp_a in "${@:2}"; do
474
+ case "$_loki_sp_a" in
475
+ --spec|--spec=*|--spec-first)
476
+ _lb=$(_loki_bun)
477
+ [ -n "$_lb" ] || { echo "loki: --spec needs bun (install from https://bun.sh)." >&2; exit 1; }
478
+ exec "$_lb" "$BUN_CLI" "$@"
479
+ ;;
480
+ esac
481
+ done
482
+ unset _loki_sp_a
483
+ fi
484
+
470
485
  # Loki 10 engine (D29, the only engine from 11.0.0). Routes `loki "<task>"`,
471
486
  # `loki owner/repo#N`, `loki quick "<task>"`, `keys` and `verify --pubkey` to engine10.
472
487
  # shellcheck disable=SC2194
@@ -477,6 +492,13 @@ case "v10" in
477
492
  _e10_args=("$@")
478
493
  case "${1:-}" in
479
494
  keys) _e10=1; _e10_hard=1 ;;
495
+ # SARIF-2: `export --sarif` has no bash implementation; it runs on bun only.
496
+ export)
497
+ for _sa in "$@"; do
498
+ case "$_sa" in --sarif) _e10=1; _e10_hard=1; _e10_args=(export-sarif "${@:2}") ;; esac
499
+ done
500
+ unset _sa
501
+ ;;
480
502
  status|verify|dashboard)
481
503
  if [ "$1" = "verify" ]; then
482
504
  for _pk in "$@"; do
@@ -495,6 +517,13 @@ case "v10" in
495
517
  unset _r10 _p10 _d
496
518
  fi
497
519
  ;;
520
+ # SPEC-FIRST-INTENT: only `plan ... --spec` is a v10 command; every other plan call stays on the legacy CLI.
521
+ plan)
522
+ for _pa in "$@"; do
523
+ [ "$_pa" = "--spec" ] && { _e10=1; _e10_hard=1; }
524
+ done
525
+ unset _pa
526
+ ;;
498
527
  ""|-*) _e10=0 ;;
499
528
  # quick: the lean small path, no PR (legacy quick never opened one). A flag-first
500
529
  # call (--help, -v) stays on the legacy quick.
@@ -710,7 +739,7 @@ fi
710
739
  # Two-token routes (provider show/list, memory list/index) match on the first
711
740
  # token only; the Bun dispatcher handles subcommand routing internally.
712
741
  case "${1:-}" in
713
- version|--version|-v|status|stats|doctor|provider|memory|rollback|internal|kpis|trust|proof|receipt|wiki|crash|control|contract|slack|queue|answer|completion|__complete)
742
+ version|--version|-v|status|stats|doctor|provider|memory|rollback|internal|kpis|trust|proof|receipt|wiki|crash|control|contract|slack|queue|issues|answer|undo|verify-pr|completion|__complete)
714
743
  # v7.5.2: rollback added (wires loki-ts/src/commands/rollback.ts).
715
744
  # v7.5.3: internal added for autonomy/run.sh phase1-hooks calls.
716
745
  # v7.5.28: kpis added (Phase K MVP: read-only KPI snapshot).
package/completions/_loki CHANGED
@@ -26,6 +26,12 @@ function _loki {
26
26
  memory)
27
27
  _loki_memory
28
28
  ;;
29
+ plan)
30
+ _loki_plan
31
+ ;;
32
+ export)
33
+ _arguments '--sarif[Write findings.sarif for a run]'
34
+ ;;
29
35
  config)
30
36
  _loki_config
31
37
  ;;
@@ -209,7 +215,10 @@ function _loki_commands {
209
215
  'otel:OpenTelemetry management'
210
216
  'wiki:Wiki commands'
211
217
  'answer:Resume a BLOCKED run with an answer'
218
+ 'verify-pr:Verify a PR against its linked issue in a sandbox'
212
219
  'queue:Overnight issue queue with a morning digest'
220
+ 'issues:Run every open issue in a repo and open PRs'
221
+ 'undo:Show what undoing a run would do (read-only plan)'
213
222
  'control:Control plane (preview, LOKI_CONTROL=1)'
214
223
  'workspace:Multi-project workspaces (preview, LOKI_WORKSPACES=1)'
215
224
  'backlog:Run every matching open issue, N in parallel'
@@ -261,6 +270,8 @@ function _loki_start {
261
270
  '--no-dashboard[Disable web dashboard]' \
262
271
  '--sandbox[Run in Docker sandbox]' \
263
272
  '--skip-memory[Skip loading memory context]' \
273
+ '--spec[Run against an edited spec file]:spec file:_files' \
274
+ '--spec-first[Write an editable spec, then stop]' \
264
275
  '--yes[Skip confirmation prompts]' \
265
276
  '-y[Skip confirmation prompts]' \
266
277
  '--budget[Cost budget limit in USD]:amount:' \
@@ -318,6 +329,14 @@ function _loki_provider {
318
329
  _describe -t cmds 'provider subcommand' cmds
319
330
  }
320
331
 
332
+ function _loki_plan {
333
+ _arguments \
334
+ '--json[Machine-readable JSON output]' \
335
+ '--verbose[Detailed per-iteration breakdown]' \
336
+ '--spec[Write editable acceptance criteria to .loki/specs/<slug>.md]' \
337
+ '*:prd file:_files'
338
+ }
339
+
321
340
  function _loki_memory {
322
341
  local -a cmds
323
342
  cmds=(
@@ -337,6 +356,9 @@ function _loki_memory {
337
356
  'pattern:Manage patterns'
338
357
  'skill:Manage skills'
339
358
  'vectors:Vector search'
359
+ 'lessons:List PR lessons (--json)'
360
+ 'learn:Learn from a merged PR'
361
+ 'forget:Delete a PR lesson'
340
362
  'help:Memory help'
341
363
  )
342
364
  _describe -t cmds 'memory subcommand' cmds
@@ -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 acp"
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"
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 --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 --help"
31
31
  COMPREPLY=( $(compgen -W "${flags}" -- "$cur") )
32
32
  return 0
33
33
  fi
@@ -57,7 +57,7 @@ _loki_completion() {
57
57
  ;;
58
58
 
59
59
  memory)
60
- local memory_cmds="list show search stats export clear dedupe index timeline consolidate economics retrieve episode pattern skill vectors help"
60
+ local memory_cmds="list show search stats export clear dedupe index timeline consolidate economics retrieve lessons learn forget episode pattern skill vectors help"
61
61
  COMPREPLY=( $(compgen -W "${memory_cmds}" -- "$cur") )
62
62
  ;;
63
63
 
@@ -142,6 +142,20 @@ _loki_completion() {
142
142
  fi
143
143
  ;;
144
144
 
145
+ export)
146
+ if [[ "$cur" == -* ]]; then
147
+ COMPREPLY=( $(compgen -W "--sarif --help" -- "$cur") )
148
+ return 0
149
+ fi
150
+ ;;
151
+
152
+ plan)
153
+ if [[ "$cur" == -* ]]; then
154
+ COMPREPLY=( $(compgen -W "--json --verbose --spec --help" -- "$cur") )
155
+ return 0
156
+ fi
157
+ ;;
158
+
145
159
  issue)
146
160
  if [[ "$cur" == -* ]]; then
147
161
  COMPREPLY=( $(compgen -W "--repo --start --dry-run --output --help" -- "$cur") )
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "11.3.1"
10
+ __version__ = "11.3.4"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -7889,6 +7889,9 @@ def _compute_cost_snapshot() -> dict:
7889
7889
  cost_recorded = False
7890
7890
  # Tokens were measured (tracker fallback) but no USD figure was recorded.
7891
7891
  cost_unknown = False
7892
+ # FC-44: sessions whose usage could not be recorded (efficiency record flagged tokens_measured:false). Any of them makes
7893
+ # every token and dollar total NOT RECORDED; the response key appears only then.
7894
+ unmeasured_sessions = 0
7892
7895
 
7893
7896
  # Read efficiency files (one JSON file per iteration/task).
7894
7897
  # Use the iteration-*.json pattern so this reader sees the same
@@ -7906,6 +7909,9 @@ def _compute_cost_snapshot() -> dict:
7906
7909
  if not isinstance(data, dict):
7907
7910
  continue
7908
7911
  measured = _record_is_measured(data)
7912
+ rec_unmeasured = data.get("tokens_measured") is False
7913
+ if rec_unmeasured:
7914
+ unmeasured_sessions += 1
7909
7915
  if measured:
7910
7916
  cost_recorded = True
7911
7917
  # Tokens are measured apart from cost: a record that priced an
@@ -7941,17 +7947,18 @@ def _compute_cost_snapshot() -> dict:
7941
7947
  for bucket, name in ((by_phase, phase), (by_model, model)):
7942
7948
  if name not in bucket:
7943
7949
  bucket[name] = {"input_tokens": 0, "output_tokens": 0, "cost_usd": 0.0,
7944
- "measured": False, "tokens_measured": False}
7950
+ "measured": False, "tokens_measured": False, "unmeasured": False}
7945
7951
  bucket[name]["input_tokens"] += inp
7946
7952
  bucket[name]["output_tokens"] += out
7947
7953
  bucket[name]["cost_usd"] += cost
7948
7954
  bucket[name]["measured"] = bucket[name]["measured"] or measured
7949
7955
  bucket[name]["tokens_measured"] = bucket[name]["tokens_measured"] or tokens_measured
7956
+ bucket[name]["unmeasured"] = bucket[name]["unmeasured"] or rec_unmeasured
7950
7957
  except (json.JSONDecodeError, KeyError, TypeError, AttributeError):
7951
7958
  pass
7952
7959
 
7953
7960
  # Fallback: read from context tracking if efficiency files have no token data
7954
- if total_input == 0 and total_output == 0:
7961
+ if total_input == 0 and total_output == 0 and not unmeasured_sessions:
7955
7962
  ctx_file = loki_dir / "context" / "tracking.json"
7956
7963
  if ctx_file.exists():
7957
7964
  try:
@@ -8024,25 +8031,26 @@ def _compute_cost_snapshot() -> dict:
8024
8031
  # set of measured records that genuinely sums to zero still renders 0.0 --
8025
8032
  # the direction that would otherwise blank real data (the v8.72.0 trap).
8026
8033
  return {
8027
- "total_input_tokens": total_input if cost_recorded else None,
8028
- "total_output_tokens": total_output if cost_recorded else None,
8029
- "total_cache_read_tokens": total_cache_read if cost_recorded else None,
8030
- "total_cache_creation_tokens": total_cache_creation if cost_recorded else None,
8034
+ **({"unmeasured_sessions": unmeasured_sessions} if unmeasured_sessions else {}),
8035
+ "total_input_tokens": total_input if cost_recorded and not unmeasured_sessions else None,
8036
+ "total_output_tokens": total_output if cost_recorded and not unmeasured_sessions else None,
8037
+ "total_cache_read_tokens": total_cache_read if cost_recorded and not unmeasured_sessions else None,
8038
+ "total_cache_creation_tokens": total_cache_creation if cost_recorded and not unmeasured_sessions else None,
8031
8039
  "total_tokens": (
8032
8040
  total_input + total_output + total_cache_read + total_cache_creation
8033
- ) if cost_recorded else None,
8041
+ ) if cost_recorded and not unmeasured_sessions else None,
8034
8042
  "cache_hit_ratio": round(total_cache_read / _read_in, 4) if _read_in > 0 else None,
8035
- "estimated_cost_usd": round(estimated_cost, 6) if cost_recorded and not cost_unknown else None,
8043
+ "estimated_cost_usd": round(estimated_cost, 6) if cost_recorded and not cost_unknown and not unmeasured_sessions else None,
8036
8044
  "cost_recorded": cost_recorded,
8037
8045
  "by_phase": {k: {
8038
- "input_tokens": v["input_tokens"] if v.get("tokens_measured") else None,
8039
- "output_tokens": v["output_tokens"] if v.get("tokens_measured") else None,
8040
- "cost_usd": round(v["cost_usd"], 6) if v.get("measured") else None,
8046
+ "input_tokens": v["input_tokens"] if v.get("tokens_measured") and not v.get("unmeasured") else None,
8047
+ "output_tokens": v["output_tokens"] if v.get("tokens_measured") and not v.get("unmeasured") else None,
8048
+ "cost_usd": round(v["cost_usd"], 6) if v.get("measured") and not v.get("unmeasured") else None,
8041
8049
  } for k, v in by_phase.items()},
8042
8050
  "by_model": {k: {
8043
- "input_tokens": v["input_tokens"] if v.get("tokens_measured") else None,
8044
- "output_tokens": v["output_tokens"] if v.get("tokens_measured") else None,
8045
- "cost_usd": round(v["cost_usd"], 6) if v.get("measured") else None,
8051
+ "input_tokens": v["input_tokens"] if v.get("tokens_measured") and not v.get("unmeasured") else None,
8052
+ "output_tokens": v["output_tokens"] if v.get("tokens_measured") and not v.get("unmeasured") else None,
8053
+ "cost_usd": round(v["cost_usd"], 6) if v.get("measured") and not v.get("unmeasured") else None,
8046
8054
  } for k, v in by_model.items()},
8047
8055
  "budget_limit": budget_limit,
8048
8056
  "budget_used": round(budget_used, 6) if budget_limit is not None and budget_used is not None else None,
@@ -13,8 +13,8 @@ An Agent Change Receipt is the JSON file a Loki 10 run seals at `.loki/runs/<run
13
13
  - `not_proven`: list of strings naming what the run did not prove.
14
14
  - `verdict`: one of `VERIFIED`, `PARTIAL`, `ALREADY_SATISFIED`, `SPEC_CONFLICT`, `FAILED` (`types.ts:44`).
15
15
  - `evidence`: list of strings (search hits and citation for an ALREADY_SATISFIED verdict).
16
- - `cost`: `{ usd (number or null), input_tokens, output_tokens, measured_sessions, total_sessions, partial_usd, source? }`.
17
- - `time`: `{ wall_s, stages }`.
16
+ - `cost`: `{ usd (number or null), input_tokens, output_tokens, cache_read_tokens?, cache_creation_tokens?, sdk_duration_ms?, measured_sessions, total_sessions, partial_usd, source? }`.
17
+ - `time`: `{ wall_s, total_s?, stages, stage_s? }`. `stages` is a disjoint partition of `total_s`: `setup` (first event to machine start), each stage, a parallel group as one bucket (for example `plan+wall`), `orchestration` gaps and `seal`, so a consumer may simply add them. `stage_s` holds each stage's own seconds (parallel members overlap, so they can add to more than their bucket). `wall_s` is the stage buckets without setup, orchestration and seal. `total_s` is elapsed seconds from the run's first event to seal (PR stage excluded); treat it as NOT RECORDED unless every bucket is a non-negative number and they sum to it within 1%. `total_s`, `stage_s` and the cache token keys are additive: older receipts omit them, which reads NOT RECORDED, never 0.
18
18
  - `events_sha256`: digest of the run event log.
19
19
  - `receipt_sha256`: sha256 of the canonical JSON with `verification` and `receipt_sha256` removed (`loki-ts/src/engine10/verify_cmd.ts:19`).
20
20
  - `verification`: `{ jwt, kid }`. `jwt` is a compact EdDSA (Ed25519) token binding the receipt hash; both are null when the receipt is unsigned (`stages/seal.ts:92-95`).
@@ -1,6 +1,6 @@
1
1
  # CLI reference
2
2
 
3
- Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.3.1. Do not edit by hand.
3
+ Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.3.4. Do not edit by hand.
4
4
  Hidden and legacy-only commands are omitted; see `docs/v10/CLI-MODERN.md` for the full inventory.
5
5
 
6
6
  | Command | Description |
@@ -61,6 +61,10 @@ Hidden and legacy-only commands are omitted; see `docs/v10/CLI-MODERN.md` for th
61
61
  | `loki queue add` | Queue issue refs |
62
62
  | `loki queue list` | Show the queue |
63
63
  | `loki queue run` | Process the queue |
64
+ | `loki issues` | Run every open issue in a repo and open PRs |
65
+ | `loki issues run` | Triage and run open issues; split too-large ones into stacked PRs |
66
+ | `loki undo` | Plan or apply an undo of a run |
67
+ | `loki verify-pr` | Verify a PR against its linked issue in a sandbox |
64
68
  | `loki answer` | Resume a BLOCKED run with an answer |
65
69
  | `loki engine10` | v10 engine router |
66
70
  | `loki engine10 run` | Run the v10 engine |