loki-mode 11.17.57 → 11.17.59

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 (80) hide show
  1. package/README.md +13 -4
  2. package/SKILL.md +3 -3
  3. package/VERSION +1 -1
  4. package/autonomy/lib/engine10-push.sh +22 -5
  5. package/autonomy/loki +384 -9
  6. package/autonomy/telemetry.sh +2 -2
  7. package/bin/loki +105 -0
  8. package/completions/_loki +13 -0
  9. package/completions/loki.bash +15 -1
  10. package/dashboard/__init__.py +1 -1
  11. package/docs/CLI-REFERENCE.md +3 -1
  12. package/docs/COMPARE-OPENCODE.md +18 -6
  13. package/docs/INSTALLATION.md +6 -2
  14. package/docs/v10/CLI-MODERN.md +5 -3
  15. package/docs/v10/PROGRESS.md +3 -0
  16. package/loki-ts/dist/loki.js +1128 -1117
  17. package/mcp/__init__.py +1 -1
  18. package/package.json +2 -2
  19. package/packages/control-plane/dist/server.js +15 -1
  20. package/packages/control-plane/ui/dist/assets/{index-CxZWgwie.css → index-DeSVrWgd.css} +1 -1
  21. package/packages/control-plane/ui/dist/assets/{index-u8cd6TRQ.js → index-Dww-8G06.js} +10 -10
  22. package/packages/control-plane/ui/dist/index.html +2 -2
  23. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  24. package/web-app/dist/assets/{AdminPage-D9vxsKmh.js → AdminPage-CCO9zGD0.js} +1 -1
  25. package/web-app/dist/assets/{Avatar-DfxBpPUo.js → Avatar-JPtFS3re.js} +1 -1
  26. package/web-app/dist/assets/{Badge-Jtp0w19_.js → Badge-1bUFOFcI.js} +1 -1
  27. package/web-app/dist/assets/{Button-Cfl_Ygum.js → Button-BQn8thxN.js} +1 -1
  28. package/web-app/dist/assets/{CockpitPage-t_xLPM1y.js → CockpitPage-olBRJMLN.js} +1 -1
  29. package/web-app/dist/assets/{ComparePage-00e9eUgR.js → ComparePage-B-o4mxlZ.js} +1 -1
  30. package/web-app/dist/assets/{ErrorBoundary-DfoBT_kK.js → ErrorBoundary-C4IN6YYt.js} +1 -1
  31. package/web-app/dist/assets/{EvidenceReceiptPanel-Cm--Zldw.js → EvidenceReceiptPanel-CH4iRJiJ.js} +1 -1
  32. package/web-app/dist/assets/{GitHubIssuesPanel-CmZoYExK.js → GitHubIssuesPanel-BNgRlwGt.js} +1 -1
  33. package/web-app/dist/assets/{GitHubPRsPanel-rehTMC_P.js → GitHubPRsPanel-B6M_lVU3.js} +1 -1
  34. package/web-app/dist/assets/{HomePage-CKgOAUqm.js → HomePage-CSlr_5vo.js} +2 -2
  35. package/web-app/dist/assets/{LoginPage-DWMk7D-V.js → LoginPage-DJhYZ0SQ.js} +1 -1
  36. package/web-app/dist/assets/{MagicPage-BdIzYkjN.js → MagicPage-B4XpvDFP.js} +1 -1
  37. package/web-app/dist/assets/{MetricsPage-DdjN5LJL.js → MetricsPage-DlgPEc5f.js} +1 -1
  38. package/web-app/dist/assets/{NotFoundPage-Cf4GHp9Z.js → NotFoundPage-oE1Fvllj.js} +1 -1
  39. package/web-app/dist/assets/{ProjectPage-BP8u2iFN.js → ProjectPage-B94pP0UO.js} +3 -3
  40. package/web-app/dist/assets/{ProjectsPage-CK7R-DIh.js → ProjectsPage-Bk67iaJq.js} +1 -1
  41. package/web-app/dist/assets/{SettingsPage-DNMqOUrM.js → SettingsPage-BGVzSJ3n.js} +1 -1
  42. package/web-app/dist/assets/{ShowcasePage-RkPgacU3.js → ShowcasePage-DtGaDxE5.js} +1 -1
  43. package/web-app/dist/assets/{SystemSettingsPage-COqYOPAP.js → SystemSettingsPage-CfyOGdC-.js} +1 -1
  44. package/web-app/dist/assets/{TeamsPage-CyBIuYhv.js → TeamsPage-CuGmdY85.js} +1 -1
  45. package/web-app/dist/assets/{TemplatesPage-5cMJ3uaP.js → TemplatesPage-Db4OZ-o0.js} +1 -1
  46. package/web-app/dist/assets/{TerminalOutput-D2as8CHU.js → TerminalOutput-B1W28fpH.js} +1 -1
  47. package/web-app/dist/assets/{activity-B0HWAVsH.js → activity-DKFtW1Dz.js} +1 -1
  48. package/web-app/dist/assets/{bell-CeapvdDm.js → bell-D2iqUEiO.js} +1 -1
  49. package/web-app/dist/assets/{bot-C9_qiFCl.js → bot-DgV5jnOz.js} +1 -1
  50. package/web-app/dist/assets/{check-ZLkbkjP8.js → check-BgJBmYEn.js} +1 -1
  51. package/web-app/dist/assets/{chevron-left-DzAOofqV.js → chevron-left-lPbv6ogy.js} +1 -1
  52. package/web-app/dist/assets/{circle-alert-C_P6Sbnq.js → circle-alert-CKhQ_hdo.js} +1 -1
  53. package/web-app/dist/assets/{clock-hlFBiyvc.js → clock-DWq8vor5.js} +1 -1
  54. package/web-app/dist/assets/{cloud-gpl8_jQe.js → cloud-BvQxG3Q2.js} +1 -1
  55. package/web-app/dist/assets/{code-xml-CJ7WRPDY.js → code-xml-aL36Csaf.js} +1 -1
  56. package/web-app/dist/assets/{database-C0waxSTC.js → database-CFzHMx2h.js} +1 -1
  57. package/web-app/dist/assets/{dollar-sign-TFqYdT4P.js → dollar-sign-C-jqbXs_.js} +1 -1
  58. package/web-app/dist/assets/{file-code-corner-Cklb7xuW.js → file-code-corner-pZ_KZ1YO.js} +1 -1
  59. package/web-app/dist/assets/{file-plus-vY6Bgsjz.js → file-plus-fRMGiUh4.js} +1 -1
  60. package/web-app/dist/assets/{globe-4A2JXvUS.js → globe-CVyRdgIZ.js} +1 -1
  61. package/web-app/dist/assets/{hammer-ZHnY2Erh.js → hammer-DRokcz-I.js} +1 -1
  62. package/web-app/dist/assets/{index-CgCOQR3S.js → index-CLY7CAQL.js} +3 -3
  63. package/web-app/dist/assets/{layers-By5ECd5H.js → layers-CEWB89or.js} +1 -1
  64. package/web-app/dist/assets/{loader-circle-yM_E0C2Q.js → loader-circle-C5OvUx9K.js} +1 -1
  65. package/web-app/dist/assets/{lock-lSNyrxDR.js → lock-TGMA_-t0.js} +1 -1
  66. package/web-app/dist/assets/{package-BKFtRuCB.js → package-QJ4Wad2J.js} +1 -1
  67. package/web-app/dist/assets/{plus-CjV1F6qp.js → plus-Dgj8mPvu.js} +1 -1
  68. package/web-app/dist/assets/{refresh-cw-DTSM4-_Q.js → refresh-cw-AGMW2syT.js} +1 -1
  69. package/web-app/dist/assets/{rotate-ccw-CiCkyt92.js → rotate-ccw-BvQ3PO0r.js} +1 -1
  70. package/web-app/dist/assets/{scroll-text-D1Ruxchx.js → scroll-text-iwC90pRp.js} +1 -1
  71. package/web-app/dist/assets/{server-DhT2dH_l.js → server-TUwkkzsm.js} +1 -1
  72. package/web-app/dist/assets/{shield-alert-CFFYVEiJ.js → shield-alert-CR3ONYJ5.js} +1 -1
  73. package/web-app/dist/assets/{thumbs-up-Dl4lQ_rS.js → thumbs-up-DC2-6Rb1.js} +1 -1
  74. package/web-app/dist/assets/{trash-2-DMJUQZ_M.js → trash-2-o9Iijmor.js} +1 -1
  75. package/web-app/dist/assets/{trending-down-C4mhp6Ua.js → trending-down-d0olJaN5.js} +1 -1
  76. package/web-app/dist/assets/{trending-up-D534cAuW.js → trending-up-BB6Q7LpE.js} +1 -1
  77. package/web-app/dist/assets/{upload-nhP5uhIQ.js → upload-5ck9hJ9r.js} +1 -1
  78. package/web-app/dist/assets/{usePolling-CWFsCezc.js → usePolling-BLGH4uFR.js} +1 -1
  79. package/web-app/dist/assets/{user-5TMGZ6m7.js → user-CNCAMMb7.js} +1 -1
  80. package/web-app/dist/index.html +1 -1
package/README.md CHANGED
@@ -26,7 +26,14 @@ The npm package installs the Bun runtime the engine needs as an optional depende
26
26
  Want to see a result before you install or spend anything?
27
27
 
28
28
  ```bash
29
- npx loki-mode tour # prints a real receipt from a past build: no key, no spend, no network
29
+ npx loki-mode start # no git repo: a real receipt, no key, no spend
30
+ npx loki-mode tour # the same receipt when you are already inside a repo
31
+ ```
32
+
33
+ `npx` downloads the package the first time, so that step needs the network. The receipt itself replays offline and checks with no provider and no key.
34
+
35
+ ```bash
36
+ npx loki-mode wow # a provider is ready: one tiny real task in a temp repo, its own receipt
30
37
  ```
31
38
 
32
39
  ## First run
@@ -57,7 +64,7 @@ Every run starts from a delivery contract derived from your task, writes checks
57
64
  loki verify # newest run; or: loki verify <run-id>
58
65
  ```
59
66
 
60
- `loki verify` re-hashes the receipt, checks its signature and checks it against the run's event log. It prints a verdict and exits 0 (VERIFIED), 1 (TAMPERED), 2 (UNCHECKED), 3 (UNSIGNED, refused unless `--allow-unsigned`), 4 (run outcome not verified) or 66 (no runs); `[ $rc -eq 0 ]` is the only safe test for "verified". Full table: [docs/exit-codes.md](docs/exit-codes.md). On another machine, export the public key with `loki keys export` and pass it with `loki verify --pubkey <file>`. A receipt claims only what its checks ran, and lists what they did not; signing proves who produced it, not that the code is bug-free. Details: [docs/SIGNED-RECEIPTS.md](docs/SIGNED-RECEIPTS.md).
67
+ `loki verify` re-hashes the receipt, checks its signature and checks it against the run's event log. It prints a verdict and exits 0 (VERIFIED), 1 (TAMPERED), 2 (UNCHECKED), 3 (UNSIGNED, refused unless `--allow-unsigned`), 4 (run outcome not verified) or 66 (no runs); `[ $rc -eq 0 ]` is the only safe test for "verified". `loki start` also requires fail-to-pass for a declared behavior change: a Wall test must fail on the old code and pass after, or the verdict stays PARTIAL (`LOKI_MUTATION_STRICT=0` opts out). Full table: [docs/exit-codes.md](docs/exit-codes.md). On another machine, export the public key with `loki keys export` and pass it with `loki verify --pubkey <file>`. A receipt claims only what its checks ran, and lists what they did not; signing proves who produced it, not that the code is bug-free. Details: [docs/SIGNED-RECEIPTS.md](docs/SIGNED-RECEIPTS.md).
61
68
 
62
69
  For a multi-repo change set, `loki start --workspace <name> "<brief>"` seals one signed `composite.json` over every child receipt, and `loki verify <run-dir>/composite.json` re-checks it offline ([docs/WORKSPACES.md](docs/WORKSPACES.md)). A composite never reads higher than its weakest child.
63
70
 
@@ -91,7 +98,7 @@ Time: 4m12s (intake 11s, plan 20s, implement 3m10s, verify 31s)
91
98
 
92
99
  | Command | What it does |
93
100
  |---------|--------------|
94
- | `loki start "<task>"` | The primary path: build a task, PRD file or issue, verify it, seal a receipt, open a PR (`--no-pr`, `--deep`, `--provider`, `--max-cost`). `loki "<task>"` and `loki owner/repo#N` are shorthand |
101
+ | `loki start "<task>"` | The command you run: same provider model as a raw session, then the harness re-runs the checks and seals a receipt (`--no-pr`, `--provider`, `--max-cost`, `--haiku` to opt the first implement onto haiku). `loki "<task>"` and `loki owner/repo#N` are shorthand. No task and no git repo shows a receipt and spends nothing |
95
102
  | `loki edit "<change>"` | One targeted change in one pass, no PR, plan or council (`--verify`, `--receipt`, `--commit`, `--dry-run`) |
96
103
  | `loki quick "<task>"` | One small task with a verify loop, no PR |
97
104
  | `loki chat` | Interactive alternative: Plan and Build modes, slash commands, `/run` starts a `loki start` run, `--attach` joins one |
@@ -106,7 +113,9 @@ Time: 4m12s (intake 11s, plan 20s, implement 3m10s, verify 31s)
106
113
  | `loki doctor [--fix] [--json]` | Check prerequisites, providers and login; `--fix` applies safe fixes |
107
114
  | `loki control serve` | Start the Control Plane (see below) |
108
115
  | `loki dashboard` | Open the Control Plane UI, starting it if needed |
109
- | `loki tour` | Show a sample receipt offline |
116
+ | `loki tour` | Show a sample receipt offline. `loki start` does this when you are not in a git repo and did not pass a task |
117
+ | `loki wow` | Same live mini-task as a normal start, in a temp repo. Offline sample when no provider is ready |
118
+ | `loki factory "<task>"` | Same as `loki start`. The policy line is printed by start |
110
119
  | `loki --help` | Everything else; `loki help <command>` for one command |
111
120
 
112
121
  Core verbs: [docs/CLI-CORE-VERBS.md](docs/CLI-CORE-VERBS.md). Every command (generated): [docs/CLI-REFERENCE.md](docs/CLI-REFERENCE.md). Engine guide, provider table, model routes, custom agents and chat: [docs/v10/GUIDE.md](docs/v10/GUIDE.md). Honest comparison with opencode: [docs/COMPARE-OPENCODE.md](docs/COMPARE-OPENCODE.md).
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ 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.17.57
6
+ # Loki Mode v11.17.59
7
7
 
8
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
 
@@ -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`, `backup`, `restore`, `proof`, `wiki`, `control`, `intent`, `kpis`, `report`, `trust`, `crash`, `contract`, `start`, `slack`, `queue`, `issues`, `undo`, `verify-pr`, `answer`, `engine10`, `help`, `chat`, `edit`, `diff`, `models`, `setup`, `quick`, `quickstart`, `init`, `template`, `verify`, `keys`, `review`, `dashboard`, `config`, `mcp`, `acp`, `stop`, `pause`, `resume`, `cancel`, `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`, `steer`
203
+ `version`, `status`, `doctor`, `provider`, `memory`, `rollback`, `backup`, `restore`, `proof`, `wiki`, `control`, `intent`, `kpis`, `report`, `trust`, `crash`, `contract`, `start`, `slack`, `queue`, `issues`, `undo`, `verify-pr`, `answer`, `engine10`, `help`, `chat`, `edit`, `diff`, `models`, `setup`, `quick`, `quickstart`, `init`, `template`, `verify`, `keys`, `review`, `dashboard`, `config`, `mcp`, `acp`, `stop`, `pause`, `resume`, `cancel`, `why`, `next`, `logs`, `ship`, `deploy`, `import`, `github`, `issue`, `ci`, `modernize`, `share`, `assets`, `export`, `notify`, `tour`, `wow`, `factory`, `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`, `steer`
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.17.57 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
486
+ **v11.17.59 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 11.17.57
1
+ 11.17.59
@@ -207,6 +207,7 @@ case "$mode" in
207
207
  # --update: the status projector. One comment carrying the marker below is edited in place (created when absent),
208
208
  # so an issue shows live run state without a new comment per event. Only a comment written by the authenticated
209
209
  # gh user counts, and the body file must carry the marker (it is built by the supervisor, never from task text).
210
+ # The PR receipt comment (<!-- loki-receipt -->) uses the same upsert: a PR number is an issue number to the API.
210
211
  _e10_upd=""
211
212
  [ "${1:-}" != "--update" ] || { _e10_upd=1; shift; }
212
213
  [ "$#" -eq 2 ] || die "usage: issue-comment [--update] <issue-ref> <body-file>"
@@ -215,16 +216,32 @@ case "$mode" in
215
216
  [ -f "$2" ] || die "body file not found: $2"
216
217
  [ -z "$_e10_local" ] || { log_info "local origin: no issue to comment on (no-op)"; exit 0; }
217
218
  if [ -n "$_e10_upd" ]; then
218
- _e10_marker='<!-- loki-status -->'
219
- grep -qF -- "$_e10_marker" "$2" || die "status body must carry $_e10_marker"
219
+ _e10_marker=""
220
+ for _e10_m in '<!-- loki-status -->' '<!-- loki-receipt -->'; do
221
+ if grep -qF -- "$_e10_m" "$2"; then _e10_marker="$_e10_m"; break; fi
222
+ done
223
+ [ -n "$_e10_marker" ] || die "status body must carry <!-- loki-status --> or <!-- loki-receipt -->"
220
224
  _e10_me="$(_e10_gh api user --jq .login 2>/dev/null)" || _e10_me=""
221
225
  _e10_cid=""
226
+ # A receipt upsert never posts on a failed lookup: that would stack a duplicate and still report success.
227
+ if [ -z "$_e10_me" ] && [ "$_e10_marker" = '<!-- loki-receipt -->' ]; then die "cannot resolve the gh user for the receipt comment lookup"; fi
222
228
  if [ -n "$_e10_me" ]; then
223
- _e10_cid="$(_e10_gh api "repos/$_e10_repo/issues/$num/comments" --paginate \
224
- --jq ".[] | select(.user.login == \"$_e10_me\") | select(.body | contains(\"$_e10_marker\")) | .id" 2>/dev/null | head -n 1)" || _e10_cid=""
229
+ if _e10_ids="$(_e10_gh api "repos/$_e10_repo/issues/$num/comments" --paginate \
230
+ --jq ".[] | select(.user.login == \"$_e10_me\") | select(.body | contains(\"$_e10_marker\")) | .id" 2>/dev/null)"; then
231
+ _e10_cid="$(printf '%s\n' "$_e10_ids" | head -n 1)"
232
+ elif [ "$_e10_marker" = '<!-- loki-receipt -->' ]; then
233
+ die "receipt comment lookup failed"
234
+ fi
225
235
  fi
226
236
  case "$_e10_cid" in
227
- '') _e10_gh issue comment "$num" --repo "$_e10_repo" --body-file "$2" || die "gh issue comment failed" ;;
237
+ '')
238
+ # A PR number is not an issue to `gh issue comment`; the receipt marker only ever rides a PR.
239
+ if [ "$_e10_marker" = '<!-- loki-receipt -->' ]; then
240
+ _e10_gh pr comment "$num" --repo "$_e10_repo" --body-file "$2" || die "gh pr comment failed"
241
+ else
242
+ _e10_gh issue comment "$num" --repo "$_e10_repo" --body-file "$2" || die "gh issue comment failed"
243
+ fi
244
+ ;;
228
245
  *[!0-9]*) die "unexpected comment id" ;;
229
246
  *) _e10_gh api -X PATCH "repos/$_e10_repo/issues/comments/$_e10_cid" -F "body=@$2" >/dev/null || die "gh api comment update failed" ;;
230
247
  esac
package/autonomy/loki CHANGED
@@ -1929,6 +1929,9 @@ show_help_all() {
1929
1929
  echo " loki start PROJ-456 # Jira issue"
1930
1930
  echo " loki quick \"add dark mode\" # Single-task mode (Loki 10 engine)"
1931
1931
  echo " loki tour # See a real sample result (no provider, no key, no spend)"
1932
+ echo " loki tour --live # Same as loki wow: a tiny real task when a provider is ready"
1933
+ echo " loki wow # Live mini-task, or the offline sample when no key is available"
1934
+ echo " loki factory \"<task>\" # loki start, and print the autonomy policy"
1932
1935
  echo " loki demo # Build a sample todo app end to end"
1933
1936
  echo " loki init -t saas-starter # Scaffold from template"
1934
1937
  echo " loki template install <src> # Install a community PRD template"
@@ -1994,7 +1997,7 @@ show_help_all() {
1994
1997
  echo " acp agent analyze api assets audit backlog backup bench cancel checkpoint (cp) ci cleanup"
1995
1998
  echo " cluster cockpit code compliance completions compound config context (ctx)"
1996
1999
  echo " cost council crash dashboard demo deploy docker docs doctor dogfood"
1997
- echo " enterprise estimate explain export failover github grill heal help"
2000
+ echo " enterprise estimate explain export factory failover github grill heal help"
1998
2001
  echo " import init intent"
1999
2002
  echo " issue keys kpis logs magic mcp memory metrics migrate modernize monitor"
2000
2003
  echo " next notify onboard open optimize otel outcomes own (handoff) pause plan preview"
@@ -2003,7 +2006,7 @@ show_help_all() {
2003
2006
  echo " serve setup setup-skill share ship spec start state stats status steer stop"
2004
2007
  echo " syslog telemetry template test tour trigger trust trust-metrics"
2005
2008
  echo " ultracode undo update verify version voice watch watchdog web welcome why"
2006
- echo " wiki workspace worktree (wt)"
2009
+ echo " wiki workspace worktree (wt) wow"
2007
2010
  echo " control"
2008
2011
  echo ""
2009
2012
  echo "Any command: loki <command> --help"
@@ -2596,7 +2599,7 @@ _loki_start_flag_kind() {
2596
2599
  case "${1%%=*}" in
2597
2600
  --provider|--brief|--budget|--cost|--prd|--issue|--isolation|--aider-model|--aider-flags|--cline-model|--compliance|--max-duration|--log-level|--bmad-project|--openspec|--mirofish-rounds|--mirofish-timeout|--output|--config|--vars|--env-file|--remote|--attempts|--mirofish-docker) _LOKI_START_FLAG_KIND=value ;;
2598
2601
  --mirofish) _LOKI_START_FLAG_KIND=optional ;;
2599
- --parallel|--allow-haiku|--regen-prd|--regenerate-prd|--regen|--fresh-prd|--bg|--background|--simple|--complex|--github|--no-dashboard|--api|--sandbox|--skip-memory|--yes|-y|--quiet|--mirofish-bg|--no-mirofish|--no-plan|--fast|--repo-fast|--full|--repo-full|--dry-run|--no-start|--worktree|-w|--pr|--prepare-pr|--ship|--detach|-d|--help|-h|--resume|--) _LOKI_START_FLAG_KIND=bool ;;
2602
+ --parallel|--allow-haiku|--haiku|--regen-prd|--regenerate-prd|--regen|--fresh-prd|--bg|--background|--simple|--complex|--github|--no-dashboard|--api|--sandbox|--skip-memory|--yes|-y|--quiet|--mirofish-bg|--no-mirofish|--no-plan|--fast|--repo-fast|--full|--repo-full|--dry-run|--no-start|--worktree|-w|--pr|--prepare-pr|--ship|--detach|-d|--help|-h|--resume|--) _LOKI_START_FLAG_KIND=bool ;;
2600
2603
  *) return 1 ;;
2601
2604
  esac
2602
2605
  # A "--flag=value" token carries its own value, so it never consumes the next one.
@@ -2624,6 +2627,73 @@ _loki_e10_resume_map() {
2624
2627
  return 0
2625
2628
  }
2626
2629
 
2630
+ # TEN-COST-01 lean levers (the bash twin of COST_PROFILES.lean in loki-ts/src/util/cost_profile.ts).
2631
+ # Fills only unset variables, so explicit env wins. Shared by --cost lean and --haiku.
2632
+ loki_lean_levers() {
2633
+ : "${LOKI_IMPLEMENT_HAIKU_FIRST:=1}" "${LOKI_E10_TRIM:=1}" "${LOKI_E10_SMALL_NO_RUNNER:=1}" "${LOKI_E10_SMALL_MAX_CHARS:=1200}"
2634
+ export LOKI_IMPLEMENT_HAIKU_FIRST LOKI_E10_TRIM LOKI_E10_SMALL_NO_RUNNER LOKI_E10_SMALL_MAX_CHARS
2635
+ }
2636
+
2637
+ # --haiku opt-in: the lean levers plus LOKI_COST_FIRST=1. Does not change the
2638
+ # default model. bin/loki strips the flag and sets the same levers before
2639
+ # engine10; this covers a direct bash start and LOKI_CONFIG_DUMP.
2640
+ loki_apply_haiku_optin() {
2641
+ local _a
2642
+ for _a in "$@"; do
2643
+ [ "$_a" = "--haiku" ] || continue
2644
+ loki_lean_levers
2645
+ : "${LOKI_COST_FIRST:=1}"
2646
+ export LOKI_COST_FIRST
2647
+ return 0
2648
+ done
2649
+ }
2650
+
2651
+ # Same fail-to-pass default as _loki_f2p_default in bin/loki. Direct bash
2652
+ # starts never see the shim. Explicit 0 or 1 wins. --help does not set it.
2653
+ loki_f2p_default() {
2654
+ case "${1:-}" in
2655
+ start|run|quick) ;;
2656
+ *) return 0 ;;
2657
+ esac
2658
+ local _a
2659
+ for _a in "$@"; do
2660
+ case "$_a" in --help|-h) return 0 ;; esac
2661
+ done
2662
+ if [ -z "${LOKI_MUTATION_STRICT:-}" ]; then
2663
+ export LOKI_MUTATION_STRICT=1
2664
+ export LOKI_F2P_DEFAULTED=1
2665
+ fi
2666
+ if [ -z "${LOKI_E10_TRIM:-}" ]; then
2667
+ export LOKI_E10_TRIM=1
2668
+ export LOKI_TRIM_DEFAULTED=1
2669
+ fi
2670
+ }
2671
+ # Names only the defaults this run actually turned on (an explicit 0 or 1 is the user's, not a default).
2672
+ loki_f2p_banner() {
2673
+ local f2p="${LOKI_F2P_DEFAULTED:-}" trim="${LOKI_TRIM_DEFAULTED:-}"
2674
+ if [ "$f2p" = "1" ] && [ "$trim" = "1" ]; then
2675
+ echo "Factory: a behavior change is verified only when a Wall test fails on the old code, and tool logs are trimmed before the next turn. Opt out: LOKI_MUTATION_STRICT=0, LOKI_E10_TRIM=0." >&2
2676
+ elif [ "$f2p" = "1" ]; then
2677
+ echo "Factory: a behavior change is verified only when a Wall test fails on the old code. Opt out: LOKI_MUTATION_STRICT=0." >&2
2678
+ elif [ "$trim" = "1" ]; then
2679
+ echo "Factory: tool logs are trimmed before the next turn. Opt out: LOKI_E10_TRIM=0." >&2
2680
+ fi
2681
+ }
2682
+
2683
+ # $1 (optional): the repo the run targets, so `loki factory ./other-repo` reports that repo's policy.
2684
+ loki_print_autonomy() {
2685
+ local pol="" f pre="" data_dir="${LOKI_DATA_DIR:-${HOME}/.loki}"
2686
+ if [ -n "${1:-}" ] && [ "$1" != "." ] && [ -d "$1" ]; then pre="${1%/}/"; fi
2687
+ for f in "${pre}.loki/policies.json" "${pre}.loki/policies.yaml" "${data_dir}/policies.json" "${data_dir}/policies.yaml"; do
2688
+ if [ -f "$f" ]; then pol="$f"; break; fi
2689
+ done
2690
+ if [ -n "$pol" ]; then
2691
+ echo "Autonomy: policy file $pol (propose, execute, operate; the file decides PR allow, draft or deny)." >&2
2692
+ else
2693
+ echo "Autonomy: execute (no policy file). Levels: propose, execute, operate." >&2
2694
+ fi
2695
+ }
2696
+
2627
2697
  cmd_start() {
2628
2698
  # First-run welcome (once): open the branded welcome page on the very
2629
2699
  # first start. Writes ~/.loki/.welcomed and never repeats; non-blocking,
@@ -2853,7 +2923,7 @@ cmd_start() {
2853
2923
  echo " PROJ-123, #123, or bare number -> generate PRD from issue"
2854
2924
  echo " BRIEF mode - a quoted one-line description (with spaces) -> fast"
2855
2925
  echo " zero-config first run; visible artifact + proof quickly"
2856
- echo " no input - analyze current directory, auto-generate PRD"
2926
+ echo " no input - analyze current directory, auto-generate PRD (outside a git repo: the offline sample receipt)"
2857
2927
  echo ""
2858
2928
  echo "Arguments:"
2859
2929
  echo " REPO Existing project directory"
@@ -2890,6 +2960,8 @@ cmd_start() {
2890
2960
  echo " --compliance PRESET Enable compliance mode (default|healthcare|fintech|government)"
2891
2961
  echo " --budget USD Per-run cost cap (default $(loki_budget_default_usd); auto-pause when exceeded)"
2892
2962
  echo " --cost PROFILE Opt-in cost profile: lean (LOKI_IMPLEMENT_HAIKU_FIRST=1, LOKI_E10_TRIM=1, LOKI_E10_SMALL_NO_RUNNER=1, LOKI_E10_SMALL_MAX_CHARS=1200 unless already set) or off"
2963
+ echo " --haiku Opt in to haiku for the first implement. Same levers as --cost lean, plus LOKI_COST_FIRST=1. A failed check climbs back to the session model. Default is the provider model"
2964
+ echo " Proof Default LOKI_MUTATION_STRICT=1 and LOKI_E10_TRIM=1. A behavior change is VERIFIED only when a Wall test fails on the old code. Tool logs are trimmed before the next turn; a command's tail is kept. Opt out: LOKI_MUTATION_STRICT=0, LOKI_E10_TRIM=0"
2893
2965
  echo " --bmad-project PATH Use BMAD Method project artifacts as input"
2894
2966
  echo " --openspec PATH Use OpenSpec change directory as input"
2895
2967
  echo " --mirofish [URL] Enable MiroFish market validation (default: localhost:5001)"
@@ -2942,7 +3014,7 @@ cmd_start() {
2942
3014
  echo " LOKI_BUDGET_LIMIT Cost cap in USD (default $(loki_budget_default_usd); empty means unlimited)"
2943
3015
  echo ""
2944
3016
  echo "Examples:"
2945
- echo " loki start # Interactive, analyze current dir"
3017
+ echo " loki start # Interactive, analyze current dir (no git repo: offline sample)"
2946
3018
  echo " loki start ./my-project # Improve an existing project"
2947
3019
  echo " loki start \"build a todo app\" # BRIEF mode (zero-config fast run)"
2948
3020
  echo " loki start --brief \"snake\" # BRIEF mode (single-word escape hatch)"
@@ -3359,11 +3431,15 @@ cmd_start() {
3359
3431
  shift
3360
3432
  ;;
3361
3433
  # TEN-COST-01: opt-in cost profile; fills only unset levers (explicit env wins).
3434
+ --haiku)
3435
+ loki_apply_haiku_optin --haiku
3436
+ shift
3437
+ ;;
3362
3438
  --cost|--cost=*)
3363
3439
  if [[ "$1" == --cost=* ]]; then _cost_val="${1#*=}"; _cost_n=1; else _cost_val="${2:-}"; _cost_n=2; fi
3364
3440
  case "$_cost_val" in
3365
- lean) : "${LOKI_IMPLEMENT_HAIKU_FIRST:=1}" "${LOKI_E10_TRIM:=1}" "${LOKI_E10_SMALL_NO_RUNNER:=1}" "${LOKI_E10_SMALL_MAX_CHARS:=1200}"
3366
- export LOKI_IMPLEMENT_HAIKU_FIRST LOKI_E10_TRIM LOKI_E10_SMALL_NO_RUNNER LOKI_E10_SMALL_MAX_CHARS LOKI_COST_PROFILE=lean
3441
+ lean) loki_lean_levers
3442
+ export LOKI_COST_PROFILE=lean
3367
3443
  echo "cost profile lean: LOKI_IMPLEMENT_HAIKU_FIRST=$LOKI_IMPLEMENT_HAIKU_FIRST LOKI_E10_TRIM=$LOKI_E10_TRIM LOKI_E10_SMALL_NO_RUNNER=$LOKI_E10_SMALL_NO_RUNNER LOKI_E10_SMALL_MAX_CHARS=$LOKI_E10_SMALL_MAX_CHARS" ;;
3368
3444
  off) ;;
3369
3445
  *) echo -e "${RED}--cost must be lean or off${NC}" >&2; exit 2 ;;
@@ -3514,6 +3590,23 @@ cmd_start() {
3514
3590
  esac
3515
3591
  done
3516
3592
 
3593
+ # No task and no git repo: do not ask for a provider and do not spend.
3594
+ # The offline receipt (same sample as loki tour) is the first thing they see.
3595
+ # An explicit provider (--provider or LOKI_PROVIDER) keeps its preflight, so a
3596
+ # missing or unknown provider still fails loudly instead of showing a sample.
3597
+ if [ -z "$brief_text" ] && [ -z "$prd_file" ] && [ -z "$positional_arg" ] \
3598
+ && [ -z "$provider" ] && [ -z "${LOKI_PROVIDER:-}" ] \
3599
+ && [ -z "$explicit_mode" ] && [ -z "${LOKI_PRD_FILE:-}" ] \
3600
+ && [ -z "$remote_url" ] && [ -z "${_ps_ws:-}" ] && [ "${_ps_deploy:-0}" != 1 ] \
3601
+ && [ -z "${bmad_project_path:-}" ] && [ -z "${openspec_change_path:-}" ]; then
3602
+ if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
3603
+ echo "No repo and no task. Showing a real receipt (no key, no spend)."
3604
+ echo ""
3605
+ wow_offline_finish
3606
+ return $?
3607
+ fi
3608
+ fi
3609
+
3517
3610
  # --remote: submit to a deployed cluster instead of building locally.
3518
3611
  #
3519
3612
  # Branches HERE, after arg parsing but BEFORE the provider pre-flight and
@@ -3601,6 +3694,12 @@ cmd_start() {
3601
3694
  fi
3602
3695
  fi
3603
3696
 
3697
+ # One line each. Printed on the path that will spend, not on --help or the
3698
+ # empty non-repo receipt above. The Loki 10 engine path prints the same
3699
+ # lines from bin/loki and does not reach here.
3700
+ loki_print_autonomy "${positional_arg:-}"
3701
+ loki_f2p_banner
3702
+
3604
3703
  # Clear any stale raw-brief marker from a PRIOR run before we decide the
3605
3704
  # mode of THIS run. Only the brief branch (below) re-writes it. Without this,
3606
3705
  # a brief run leaves .loki/state/brief.txt behind and a later non-brief run
@@ -16490,6 +16589,266 @@ print('{}{}'.format(iters, rng_str))
16490
16589
  return 0
16491
16590
  }
16492
16591
 
16592
+ # loki wow: a tiny real Loki 10 task in a temp repo, or the offline tour when no provider is ready.
16593
+ wow_offline_finish() {
16594
+ echo "No live provider for this run. Showing the offline sample (no key, no spend)."
16595
+ echo ""
16596
+ cmd_demo --offline
16597
+ echo ""
16598
+ echo "Ready for your repo? loki start"
16599
+ }
16600
+
16601
+ # Heuristic, not an auth check: an installed claude CLI with a key, an OAuth token,
16602
+ # or a config dir counts as ready. A logged-out install passes this and then fails
16603
+ # the live run; cmd_wow reports that failure and its exit code, it never hides it.
16604
+ wow_provider_ready() {
16605
+ local p="${1:-}"
16606
+ [ -n "$p" ] || p="${LOKI_PROVIDER:-claude}"
16607
+ case "$p" in
16608
+ claude)
16609
+ command -v claude >/dev/null 2>&1 || return 1
16610
+ if [ -n "${ANTHROPIC_API_KEY:-}${CLAUDE_CODE_OAUTH_TOKEN:-}" ]; then return 0; fi
16611
+ [ -e "${HOME}/.claude.json" ] || [ -d "${HOME}/.claude" ] || return 1
16612
+ return 0
16613
+ ;;
16614
+ opencode|codex|cline|aider)
16615
+ command -v "$p" >/dev/null 2>&1
16616
+ ;;
16617
+ *)
16618
+ return 1
16619
+ ;;
16620
+ esac
16621
+ }
16622
+
16623
+ # Prints the newest receipt under $1/.loki/runs. Returns 1 when none was written.
16624
+ wow_show_receipt() {
16625
+ local demo_dir="$1" receipt vrc=0
16626
+ receipt="$(python3 - "$demo_dir/.loki/runs" <<'PY'
16627
+ import os, sys
16628
+ root, best = sys.argv[1], None
16629
+ for d, _, files in os.walk(root):
16630
+ if "receipt.json" in files:
16631
+ p = os.path.join(d, "receipt.json")
16632
+ if best is None or os.path.getmtime(p) > os.path.getmtime(best):
16633
+ best = p
16634
+ print(best or "")
16635
+ PY
16636
+ )" || receipt=""
16637
+ if [ -z "$receipt" ]; then
16638
+ return 1
16639
+ fi
16640
+ echo ""
16641
+ echo "Receipt: $receipt"
16642
+ python3 - "$receipt" <<'PY'
16643
+ import json, sys
16644
+ try:
16645
+ with open(sys.argv[1], encoding="utf-8") as fh:
16646
+ r = json.load(fh)
16647
+ if not isinstance(r, dict):
16648
+ raise ValueError("not a JSON object")
16649
+ except (OSError, ValueError) as exc:
16650
+ print(f"Outcome: unreadable receipt ({exc.__class__.__name__}); loki verify below is the check")
16651
+ sys.exit(0)
16652
+ verdict = str(r.get("verdict") or "unknown")
16653
+ cost = r.get("cost") if isinstance(r.get("cost"), dict) else {}
16654
+ usd = cost.get("usd")
16655
+ tokens = 0
16656
+ for k in ("input_tokens", "output_tokens", "cache_read_tokens", "cache_creation_tokens"):
16657
+ try:
16658
+ tokens += int(cost.get(k) or 0)
16659
+ except (TypeError, ValueError):
16660
+ pass
16661
+ np = r.get("not_proven") if isinstance(r.get("not_proven"), list) else []
16662
+ print(f"Outcome: {verdict}")
16663
+ print(f"Cost: ${usd:.4f}" if isinstance(usd, (int, float)) else "Cost: not recorded on the receipt")
16664
+ print(f"Tokens: {tokens}")
16665
+ print("PROVEN: sealed verdict VERIFIED" if verdict == "VERIFIED" else f"PROVEN: no verified claim (verdict {verdict})")
16666
+ print("NOT PROVEN:")
16667
+ for item in np or ["none"]:
16668
+ print(f" - {item}")
16669
+ PY
16670
+ echo ""
16671
+ echo "Verify offline:"
16672
+ (cd "$demo_dir" && "$SKILL_DIR/bin/loki" verify) || vrc=$?
16673
+ if [ "$vrc" = "0" ]; then
16674
+ echo "loki verify exited 0"
16675
+ else
16676
+ echo "loki verify exited $vrc (the receipt did not check out; that is the evidence)"
16677
+ fi
16678
+ return 0
16679
+ }
16680
+
16681
+ # Removes only a directory this command created: a direct child of the temp root named loki-wow.*.
16682
+ wow_cleanup_dir() {
16683
+ local d="${1:-}" root
16684
+ [ -n "$d" ] && [ -d "$d" ] && [ ! -L "$d" ] || return 0
16685
+ root="$(cd "${TMPDIR:-/tmp}" 2>/dev/null && pwd -P)" || return 0
16686
+ case "$d" in "$root"/loki-wow.*) ;; *) return 0 ;; esac
16687
+ [ "$(dirname -- "$d")" = "$root" ] || return 0
16688
+ rm -rf -- "$d"
16689
+ }
16690
+
16691
+ cmd_wow() {
16692
+ local offline=false dry_run=false keep=false provider="" max_cost="2"
16693
+ while [[ $# -gt 0 ]]; do
16694
+ case "$1" in
16695
+ --help|-h)
16696
+ echo "loki wow - a tiny real task in a temporary git repo"
16697
+ echo ""
16698
+ echo "Creates a temp repo, runs one small fix through the Loki 10 engine,"
16699
+ echo "seals a receipt, and prints PROVEN vs NOT PROVEN, cost and tokens."
16700
+ echo "With no provider key it runs the offline sample instead (loki tour)."
16701
+ echo "A failed live run shows its own receipt and exit code, never the sample."
16702
+ echo ""
16703
+ echo "Usage: loki wow [--offline] [--dry-run] [--keep] [--provider P] [--max-cost N]"
16704
+ echo ""
16705
+ echo " --offline Always show the offline sample"
16706
+ echo " --dry-run Print the plan. No model call, no spend"
16707
+ echo " --keep Keep the temp repo (default: removed after the receipt is printed)"
16708
+ echo " --provider P claude (default) or opencode, codex, cline, aider"
16709
+ echo " --max-cost N Hard per-run cap in USD, a positive number (default 2). budgets.per_run still applies"
16710
+ echo ""
16711
+ echo "loki tour stays the offline sample. loki tour --live is this command."
16712
+ echo "Ready for your repo? loki start"
16713
+ return 0
16714
+ ;;
16715
+ --offline) offline=true; shift ;;
16716
+ --dry-run) dry_run=true; shift ;;
16717
+ --keep) keep=true; shift ;;
16718
+ --provider)
16719
+ provider="${2:-}"
16720
+ if [ -z "$provider" ]; then echo "loki wow: --provider requires a value" >&2; return 1; fi
16721
+ shift 2
16722
+ ;;
16723
+ --provider=*) provider="${1#*=}"; shift ;;
16724
+ --max-cost)
16725
+ max_cost="${2:-}"
16726
+ if [ -z "$max_cost" ]; then echo "loki wow: --max-cost requires a value" >&2; return 1; fi
16727
+ shift 2
16728
+ ;;
16729
+ --max-cost=*) max_cost="${1#*=}"; shift ;;
16730
+ *)
16731
+ echo "loki wow: unknown option: $1" >&2
16732
+ echo "Run 'loki wow --help'." >&2
16733
+ return 1
16734
+ ;;
16735
+ esac
16736
+ done
16737
+ if ! [[ "$max_cost" =~ ^[0-9]+(\.[0-9]+)?$ ]] || ! awk -v c="$max_cost" 'BEGIN { exit !(c > 0) }'; then
16738
+ echo "loki wow: --max-cost must be a positive number of USD, got: $max_cost" >&2
16739
+ return 2
16740
+ fi
16741
+
16742
+ if [ "$offline" = true ]; then
16743
+ wow_offline_finish
16744
+ return $?
16745
+ fi
16746
+
16747
+ local use_provider="${provider:-${LOKI_PROVIDER:-claude}}"
16748
+ case "$use_provider" in
16749
+ claude|opencode|codex|cline|aider) ;;
16750
+ *) echo "loki wow: unknown provider '$use_provider' (use claude, opencode, codex, cline or aider)" >&2; return 2 ;;
16751
+ esac
16752
+ if ! wow_provider_ready "$use_provider"; then
16753
+ if [ "$dry_run" = true ]; then
16754
+ echo "loki wow: no provider ready for '$use_provider'. A real run would show the offline sample."
16755
+ echo "Ready for your repo? loki start"
16756
+ return 0
16757
+ fi
16758
+ wow_offline_finish
16759
+ return $?
16760
+ fi
16761
+
16762
+ local task='Make greet() in greet.js return the string hello so `node --test greet.test.js` passes. Do not change the test.'
16763
+ echo "loki wow: temp repo, provider $use_provider, max-cost \$$max_cost, no PR (local receipt)."
16764
+ echo "Task: $task"
16765
+ if [ "$dry_run" = true ]; then
16766
+ echo "[dry-run] Would create a git repo with a failing node:test and run:"
16767
+ echo " loki start \"<task>\" --no-pr --provider $use_provider --max-cost $max_cost"
16768
+ echo "Then print the receipt, PROVEN vs NOT PROVEN, and: Ready for your repo? loki start"
16769
+ return 0
16770
+ fi
16771
+
16772
+ local demo_dir temp_root
16773
+ temp_root="$(cd "${TMPDIR:-/tmp}" 2>/dev/null && pwd -P)" || { echo "loki wow: cannot resolve the temp root" >&2; return 1; }
16774
+ demo_dir="$(mktemp -d "${temp_root}/loki-wow.XXXXXXXX")" || return 1
16775
+ if [ "$keep" != true ]; then
16776
+ # shellcheck disable=SC2064 # expand demo_dir now; it is local to this call
16777
+ trap "wow_cleanup_dir '$demo_dir'; trap - INT TERM; exit 130" INT TERM
16778
+ fi
16779
+ printf '%s\n' '{ "type": "module", "name": "loki-wow" }' > "$demo_dir/package.json"
16780
+ printf '%s\n' 'export function greet() { return "hi"; }' > "$demo_dir/greet.js"
16781
+ printf '%s\n' \
16782
+ 'import assert from "node:assert/strict";' \
16783
+ 'import test from "node:test";' \
16784
+ 'import { greet } from "./greet.js";' \
16785
+ 'test("greet says hello", () => { assert.equal(greet(), "hello"); });' > "$demo_dir/greet.test.js"
16786
+ # Inherited GIT_DIR and friends would point -C at the caller's repo; signing or hooks could fail the commit.
16787
+ if ! (
16788
+ unset GIT_DIR GIT_WORK_TREE GIT_COMMON_DIR GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_PREFIX
16789
+ g() { git -c commit.gpgsign=false -c core.hooksPath=/dev/null -C "$demo_dir" "$@"; }
16790
+ g init -q && g config user.email "loki-wow@example.com" && g config user.name "Loki Wow" \
16791
+ && g add package.json greet.js greet.test.js && g commit -q -m "failing greet"
16792
+ ); then
16793
+ echo "loki wow: could not set up the temp git repo" >&2
16794
+ if [ "$keep" != true ]; then trap - INT TERM; wow_cleanup_dir "$demo_dir"; fi
16795
+ return 1
16796
+ fi
16797
+ echo "Directory: $demo_dir"
16798
+ local rc=0
16799
+ (
16800
+ cd "$demo_dir" && LOKI_ASSUME_YES=1 "$SKILL_DIR/bin/loki" start "$task" --no-pr --provider "$use_provider" --max-cost "$max_cost"
16801
+ ) || rc=$?
16802
+ if ! wow_show_receipt "$demo_dir"; then
16803
+ echo ""
16804
+ if [ "$rc" != "0" ]; then
16805
+ echo "The live mini-task exited $rc before a receipt was sealed (often a provider that is installed but not logged in)."
16806
+ echo "Nothing below is the result of this run. It is the offline sample, for reference."
16807
+ echo ""
16808
+ cmd_demo --offline
16809
+ else
16810
+ echo "No receipt file was written. The run summary above is the record."
16811
+ fi
16812
+ elif [ "$rc" != "0" ]; then
16813
+ echo ""
16814
+ echo "The live mini-task exited $rc. The receipt above is this run's own result."
16815
+ fi
16816
+ if [ "$keep" = true ]; then
16817
+ echo ""
16818
+ echo "Kept: $demo_dir (remove it with: rm -rf \"$demo_dir\")"
16819
+ else
16820
+ trap - INT TERM
16821
+ wow_cleanup_dir "$demo_dir"
16822
+ fi
16823
+ echo ""
16824
+ echo "Ready for your repo? loki start"
16825
+ return "$rc"
16826
+ }
16827
+
16828
+ cmd_factory() {
16829
+ if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
16830
+ echo "loki factory \"<task|prd|issue>\" - same as loki start"
16831
+ echo ""
16832
+ echo "loki start prints the autonomy policy and runs. factory does not change that."
16833
+ echo "It does not write a policy file."
16834
+ echo ""
16835
+ echo "Autonomy levels (unchanged):"
16836
+ echo " propose plan and ask before changing the tree"
16837
+ echo " execute build, verify, seal a receipt, open a PR (default when no policy file)"
16838
+ echo " operate execute, and deploy only when you pass --deploy"
16839
+ echo ""
16840
+ echo "A .loki/policies.json or policies.yaml (repo, or LOKI_DATA_DIR, or ~/.loki) still decides"
16841
+ echo "allow, approval (draft PR) or deny."
16842
+ echo "When the contract cannot be satisfied the run stops with one question (BLOCKED)."
16843
+ echo "The summary still prints outcome, receipt, cost and the next command."
16844
+ echo ""
16845
+ echo "loki start keeps the provider model. Pass --haiku (or --cost lean) to try haiku for"
16846
+ echo "the first implement; a failed check climbs back. --max-cost stays the hard cap."
16847
+ return 0
16848
+ fi
16849
+ exec "$SKILL_DIR/bin/loki" start "$@"
16850
+ }
16851
+
16493
16852
  # Demo mode - build a real project from a bundled PRD template
16494
16853
  cmd_demo() {
16495
16854
  # Handle --help
@@ -16517,6 +16876,8 @@ cmd_demo() {
16517
16876
  echo "Examples:"
16518
16877
  echo " loki demo --offline # Replay a sample receipt (no spend)"
16519
16878
  echo " loki tour # Same as 'loki demo --offline'"
16879
+ echo " loki tour --live # Tiny real task (loki wow); offline sample if no provider"
16880
+ echo " loki wow # Live mini-task, or the offline sample with no key"
16520
16881
  echo " loki demo # Build todo app in temp dir"
16521
16882
  echo " loki demo --dir ~/demo-project # Build in specific directory"
16522
16883
  echo " loki demo --provider codex # Use Codex instead of Claude"
@@ -22420,6 +22781,9 @@ main() {
22420
22781
  if declare -f loki_maybe_apply_config_file >/dev/null 2>&1; then
22421
22782
  loki_maybe_apply_config_file "$@"
22422
22783
  fi
22784
+ # --haiku is opt-in. The dump below shows the levers when the flag is present.
22785
+ loki_apply_haiku_optin "$@"
22786
+ loki_f2p_default "$command" "$@"
22423
22787
  # #691: documented observation hook. When LOKI_CONFIG_DUMP=1, print
22424
22788
  # the resolved LOKI_* environment (after the config pre-pass AND any
22425
22789
  # ambient env) and exit 0 WITHOUT running a build. Lets operators and
@@ -22476,13 +22840,24 @@ main() {
22476
22840
  demo)
22477
22841
  cmd_demo "$@"
22478
22842
  ;;
22843
+ wow)
22844
+ cmd_wow "$@"
22845
+ ;;
22846
+ factory)
22847
+ cmd_factory "$@"
22848
+ ;;
22479
22849
  tour)
22480
22850
  # Zero-key/zero-spend taste path: an alias for 'demo --offline' that
22481
22851
  # replays a bundled real Evidence Receipt. --help routes straight to
22482
- # the demo help (which documents --offline / tour); otherwise inject
22483
- # --offline ahead of any user args.
22852
+ # the demo help (which documents --offline / tour); --live is loki wow;
22853
+ # otherwise inject --offline ahead of any user args.
22484
22854
  if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
22485
22855
  cmd_demo --help
22856
+ echo " loki tour --live # Tiny real task (same as loki wow)"
22857
+ echo " loki wow # Live mini-task, or this sample with no key"
22858
+ elif [ "${1:-}" = "--live" ]; then
22859
+ shift
22860
+ cmd_wow "$@"
22486
22861
  else
22487
22862
  cmd_demo --offline "$@"
22488
22863
  fi
@@ -170,7 +170,7 @@ _loki_known_command() {
170
170
  |audit|bench|checkpoint|ci|cleanup|cluster|cockpit|code\
171
171
  |completion|completions|compliance|compound|config|context|control|cost|council|cp\
172
172
  |crash|ctx|dashboard|demo|deploy|docker|docs|doctor\
173
- |dogfood|enterprise|explain|export|failover|github|grill|handoff\
173
+ |dogfood|enterprise|explain|export|factory|failover|github|grill|handoff\
174
174
  |heal|help|import|init|internal|issue|kpis|logs\
175
175
  |magic|mcp|memory|metrics|migrate|modernize|monitor|next\
176
176
  |notify|onboard|open|optimize|otel|own|pause|plan\
@@ -180,7 +180,7 @@ _loki_known_command() {
180
180
  |ship|spec|start|state|stats|status|steer|stop\
181
181
  |syslog|telemetry|template|test|tour|trigger|trust|trust-metrics\
182
182
  |ultracode|update|verify|version|voice|watch|watchdog|web\
183
- |welcome|why|wiki|worktree|wt)
183
+ |welcome|why|wiki|worktree|wow|wt)
184
184
  printf '%s' "$1" ;;
185
185
  *)
186
186
  printf 'other' ;;