loki-mode 11.4.2 → 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.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/chat.sh +6 -3
- package/autonomy/lib/engine10-push.sh +19 -1
- package/autonomy/lib/help-core.sh +1 -1
- package/autonomy/lib/proof-generator.py +23 -5
- package/autonomy/lib/proof-verify.py +607 -5
- package/autonomy/lib/run-summary.sh +17 -1
- package/autonomy/lib/setup-requirements.json +35 -0
- package/autonomy/loki +232 -36
- package/autonomy/provider-offer.sh +95 -47
- package/autonomy/route.sh +38 -6
- package/autonomy/run.sh +42 -14
- package/autonomy/setup-wizard.sh +19 -10
- package/autonomy/verify.sh +40 -1
- package/completions/_loki +3 -1
- package/completions/loki.bash +9 -3
- package/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +3 -1
- package/docs/EVALUATING.md +27 -0
- package/docs/HARNESS-INTELLIGENCE-PLAN.md +20 -0
- package/docs/INSTALLATION.md +1 -1
- package/docs/KNOWN-ISSUES.md +10 -1
- package/docs/PROOF-PASSPORT.md +114 -0
- package/docs/alternative-installations.md +103 -0
- package/docs/cost-controls.md +139 -0
- package/docs/environment-variables.md +36 -0
- package/docs/exit-codes.md +102 -2
- package/docs/spec-first-intent.md +29 -0
- package/docs/v10/CLI-MODERN.md +2 -2
- package/docs/v10/ENGINE.md +32 -0
- package/loki-ts/data/model-pricing.json +1 -0
- package/loki-ts/dist/loki.js +1095 -1043
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +1721 -707
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/plugins/loki-mode/README.md +41 -1
- package/plugins/loki-mode/commands/handoff.md +12 -0
- package/plugins/loki-mode/commands/loki-verify.md +9 -2
- package/plugins/loki-mode/commands/start.md +20 -0
- package/plugins/loki-mode/hooks/hooks.json +11 -0
- package/plugins/loki-mode/scripts/loki-stop-verify.sh +84 -0
- package/web-app/dist/assets/{AdminPage-CYJ2BWRC.js → AdminPage-Cbu3pXL8.js} +1 -1
- package/web-app/dist/assets/{Avatar-DdK4wynI.js → Avatar-DGqGGcGx.js} +1 -1
- package/web-app/dist/assets/{Badge-CrX3MI7J.js → Badge-Bhlipt6v.js} +1 -1
- package/web-app/dist/assets/{Button-709-wwGM.js → Button-CpN2sO61.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-BapdTInO.js → CockpitPage-BqeDJwdL.js} +1 -1
- package/web-app/dist/assets/{ComparePage-DT99pGvA.js → ComparePage-DUieA2ba.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-B0uJSys8.js → ErrorBoundary-DTWsYrOm.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-BtMFgElP.js → EvidenceReceiptPanel-BU_B9X19.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-DjJuU941.js → GitHubIssuesPanel-DEZoLOsP.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-HXfEX1BC.js → GitHubPRsPanel-BEsnrq7Y.js} +1 -1
- package/web-app/dist/assets/{HomePage-Cqyves-S.js → HomePage-BoUVuq7h.js} +2 -2
- package/web-app/dist/assets/{LoginPage-jUbtC7_Y.js → LoginPage-CmOED7vb.js} +1 -1
- package/web-app/dist/assets/{MagicPage-DHRsqjgR.js → MagicPage-DATZitrZ.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-B-pED05R.js → MetricsPage-DGL1v0I-.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-CsbUs21R.js → NotFoundPage-C2WgOjZd.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-BtlLEQwB.js → ProjectPage-BMi1tepj.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-DaRbRjSp.js → ProjectsPage-vc3y5YPh.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-DALrtP3F.js → SettingsPage-kbq0Ftvi.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-CoPHSNP0.js → ShowcasePage-Bn6Q8Kbg.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-kOuSN50O.js → SystemSettingsPage-Basmhs_b.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-DGWK0LMp.js → TeamsPage-BTqOc4TR.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-C-_10CwA.js → TemplatesPage-2P9002VL.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-Cz_vPbXL.js → TerminalOutput-CAoSPBrg.js} +1 -1
- package/web-app/dist/assets/{activity-icIsXJVa.js → activity-BcWVWCqU.js} +1 -1
- package/web-app/dist/assets/{bell-DbPR2_4r.js → bell-CYRqqgZ6.js} +1 -1
- package/web-app/dist/assets/{bot-DvjP3Yh5.js → bot-CU7gdn3g.js} +1 -1
- package/web-app/dist/assets/{check-D1OBxHeU.js → check-DLlCpz9V.js} +1 -1
- package/web-app/dist/assets/{chevron-left-D09jDZ29.js → chevron-left-CE9Cb30C.js} +1 -1
- package/web-app/dist/assets/{circle-alert-DyZMLOcC.js → circle-alert-uou4bjua.js} +1 -1
- package/web-app/dist/assets/{clock-CdpdJTId.js → clock-C_dSJcDX.js} +1 -1
- package/web-app/dist/assets/{cloud-CoLTlmoj.js → cloud-DZ22ITF6.js} +1 -1
- package/web-app/dist/assets/{code-xml-DrkE2ZZY.js → code-xml-BrJS0hhS.js} +1 -1
- package/web-app/dist/assets/{database-CMQQuM2R.js → database-D2HOmxtl.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-CuioDaOG.js → dollar-sign-CQ1vK_6q.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-Cx9j9K1S.js → file-code-corner-w2vpGm5d.js} +1 -1
- package/web-app/dist/assets/{file-plus-CYD2zaaI.js → file-plus-DlF6wjkD.js} +1 -1
- package/web-app/dist/assets/{globe-6w-hnQkL.js → globe-Dy3lBJg1.js} +1 -1
- package/web-app/dist/assets/{hammer-BpqtautL.js → hammer-C3xIiRXN.js} +1 -1
- package/web-app/dist/assets/{index-Dzs-9EgJ.js → index-4t-_IW2y.js} +3 -3
- package/web-app/dist/assets/{layers-D5hd7jb7.js → layers-Y8Fs8qXI.js} +1 -1
- package/web-app/dist/assets/{loader-circle-C6Y9x_7H.js → loader-circle-CxgN1v4m.js} +1 -1
- package/web-app/dist/assets/{lock-D51L7rYh.js → lock-DFFNbXDs.js} +1 -1
- package/web-app/dist/assets/{package-BJF8hkP8.js → package-5e6qCTUg.js} +1 -1
- package/web-app/dist/assets/{plus-D5kUQ79n.js → plus-C0Go_ytj.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-BKdlCa7F.js → refresh-cw-D4i-NW3o.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-_bd_YI1e.js → rotate-ccw-YlKkiUW6.js} +1 -1
- package/web-app/dist/assets/{scroll-text-DbkegIxF.js → scroll-text-4qXOHTap.js} +1 -1
- package/web-app/dist/assets/{server-DAwqFIsq.js → server-BB6zXNp9.js} +1 -1
- package/web-app/dist/assets/{shield-alert-BuR1tPHu.js → shield-alert-D4tzjB1H.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-BF6p3mRd.js → thumbs-up-DZiRwdFj.js} +1 -1
- package/web-app/dist/assets/{trash-2-BVpnkqqz.js → trash-2-Dv_LkRIK.js} +1 -1
- package/web-app/dist/assets/{trending-down-DpsDvRwW.js → trending-down-BJYp9PQe.js} +1 -1
- package/web-app/dist/assets/{trending-up-mFogTjt3.js → trending-up-BTcXLklK.js} +1 -1
- package/web-app/dist/assets/{upload-4T8zpBsi.js → upload-fcHqwOxr.js} +1 -1
- package/web-app/dist/assets/{usePolling-DPXQv8WO.js → usePolling-BeJYw_4L.js} +1 -1
- package/web-app/dist/assets/{user-BYGIFaTm.js → user-BcDwUCsO.js} +1 -1
- package/web-app/dist/index.html +1 -1
package/docs/INSTALLATION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Loki Mode, by [Autonomi](https://www.autonomi.dev/), turns a spec or an issue into a verified pull request with a receipt you can check. This page covers installing it, a first run, and the options around it.
|
|
4
4
|
|
|
5
|
-
**Version:** v11.
|
|
5
|
+
**Version:** v11.5.1
|
|
6
6
|
|
|
7
7
|
**Engine note:** `loki start` is the primary command. `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` all run the Loki 10 engine, whatever the flag order or input form (PRD file, issue ref, task or one-word brief). The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, or for one call when a flag Loki 10 cannot honor is present. See the [user guide](v10/GUIDE.md) and the [5-minute quickstart](QUICKSTART.md).
|
|
8
8
|
|
package/docs/KNOWN-ISSUES.md
CHANGED
|
@@ -4,4 +4,13 @@ Issues in the current release that are known and not yet fixed. Report new ones
|
|
|
4
4
|
|
|
5
5
|
## Which engine runs
|
|
6
6
|
|
|
7
|
-
From 11.4.0, `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` run the Loki 10 engine whatever the flag order or input form. The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, or for one call when a flag Loki 10 cannot honor is present (`--simple`, `--parallel`, `--sandbox`, ...). Check with `loki route start <args
|
|
7
|
+
From 11.4.0, `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` run the Loki 10 engine whatever the flag order or input form. The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, for a provider with no Loki 10 invoker, for a PRD over 100000 bytes, or for one call when a flag Loki 10 cannot honor is present (`--simple`, `--parallel`, `--sandbox`, ...). Check with `loki route start <args> --json`: it reports `engine`, `adapter`, `reason` and `capability_differences`. The full table is in the Routing contract section of `docs/exit-codes.md`.
|
|
8
|
+
|
|
9
|
+
## Exit codes
|
|
10
|
+
|
|
11
|
+
The exit code of every command is listed in `docs/exit-codes.md`. Two things are kept as they are for compatibility:
|
|
12
|
+
|
|
13
|
+
- `loki run` (deprecated alias of `loki start <issue-ref>`) exits 1 on an unknown option, not 64.
|
|
14
|
+
- `loki start` without `LOKI_DURABLE_STATE=1` has no finer run-outcome signal than 0 versus nonzero.
|
|
15
|
+
|
|
16
|
+
An empty diff has a distinct exit code only for `loki verify` (3). `loki quick`, `loki start` and `loki run` do not define one.
|
package/docs/PROOF-PASSPORT.md
CHANGED
|
@@ -29,3 +29,117 @@ trust limitations, but no repository or machine-specific paths.
|
|
|
29
29
|
Proof Passport does not currently sign the passport itself. Receipt signature
|
|
30
30
|
status is reported separately and must not be interpreted as a passport
|
|
31
31
|
signature.
|
|
32
|
+
|
|
33
|
+
## Verification record
|
|
34
|
+
|
|
35
|
+
Status: v1 (schema_version 1). Closes review finding LM-005: a passing outcome label could be misread when checks were not performed.
|
|
36
|
+
|
|
37
|
+
Implementation: the verification-record section of `autonomy/lib/proof-verify.py` (CLI: `proof-verify.py <label|summary|json> <file>`). Both routes of `loki verify` and `loki proof show` use this one module, so the bash and Bun paths cannot drift.
|
|
38
|
+
|
|
39
|
+
### Why three properties
|
|
40
|
+
|
|
41
|
+
A single "verified" word hides three different questions. The record answers each one separately and never lets one stand in for another.
|
|
42
|
+
|
|
43
|
+
1. **Integrity.** Is this record the one that was written, unaltered?
|
|
44
|
+
2. **Execution validity.** Did the checks run against the code in front of you, and in what environment?
|
|
45
|
+
3. **Requirement coverage.** Do the checks that ran actually cover what was asked for?
|
|
46
|
+
|
|
47
|
+
A signature alone proves neither execution validity nor requirement coverage. A signed record can describe checks run on a different commit, on a dirty tree, or against only some of the requirements. The signature says the bytes are unchanged. It says nothing about whether the claims in those bytes are current or complete.
|
|
48
|
+
|
|
49
|
+
### Property 1: integrity
|
|
50
|
+
|
|
51
|
+
| status | meaning |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| `valid` | `verification.hash` matches the canonical bytes, gpg (when present) verifies, the recorded headline matches the headline re-derived from the facts, and the cost claim is coherent. |
|
|
54
|
+
| `invalid` | Any of the above failed. The label becomes `NOT VERIFIED (integrity failed ...)` regardless of what the checks say. |
|
|
55
|
+
| `not_recorded` | The record carries no hash. `.loki/verify/evidence.json` is always in this state: it is unhashed and unsigned. |
|
|
56
|
+
| `unchecked` | The integrity code could not run. |
|
|
57
|
+
|
|
58
|
+
The Ed25519 attestation is reported as present but is not verified inside the record. Use `loki proof verify --jwks` for that.
|
|
59
|
+
|
|
60
|
+
### Property 2: execution validity
|
|
61
|
+
|
|
62
|
+
Recorded with every receipt:
|
|
63
|
+
|
|
64
|
+
- `git.head_sha` and `git.dirty` (dirty ignores `.loki/`), plus `git.tree_sha256` when the generator computed it.
|
|
65
|
+
- `environment`: os, machine, python, node, bun and git versions, as found.
|
|
66
|
+
|
|
67
|
+
Status:
|
|
68
|
+
|
|
69
|
+
| status | meaning |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| `fresh` | Recorded HEAD equals live HEAD and the tree digest (or clean flag) still matches. |
|
|
72
|
+
| `stale` | HEAD moved, or the working tree changed since the checks ran. Every previously passed check is reported as `stale`, and the label is `STALE (...)`. |
|
|
73
|
+
| `unknown` | Not enough was recorded to compare (older receipts, no git tree). Unknown is never promoted to fresh. The label carries `revision freshness unknown`. |
|
|
74
|
+
|
|
75
|
+
### Property 3: requirement coverage
|
|
76
|
+
|
|
77
|
+
Read from `.loki/state/requirements-map.json`:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{"requirements": [{"id": "R1", "text": "...", "checks": ["lint"], "status": "covered"}]}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
| status | meaning |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `recorded` | `total`, `covered`, `uncovered` and `uncovered_ids` are filled in. Uncovered requirements appear in the label. |
|
|
86
|
+
| `not_recorded` | No map exists. Coverage is unknown, not zero. Counts are `null`. |
|
|
87
|
+
| `unreadable` | The file exists but is not a valid map. Counts are `null`. |
|
|
88
|
+
|
|
89
|
+
`covered_but_check_not_passed` lists covered requirements whose named check did not pass. Matching check ids to gate names is best effort.
|
|
90
|
+
|
|
91
|
+
### Per-check status
|
|
92
|
+
|
|
93
|
+
Every check is exactly one of: `passed`, `failed`, `skipped`, `not_run`, `stale`.
|
|
94
|
+
|
|
95
|
+
Recorded words map as follows: pass-like words (`pass`, `passed`, `verified`, `ok`, `success`) become `passed`; fail-like words (`fail`, `failed`, `blocked`, `weakened`, `error`) become `failed`; `skipped` and `disabled` become `skipped`; `stale` stays `stale`. Everything else, including `inconclusive` and empty, becomes `not_run`. A check that did not reach a conclusion never reads as passed.
|
|
96
|
+
|
|
97
|
+
### Label rules
|
|
98
|
+
|
|
99
|
+
Evaluated in this order, first match wins:
|
|
100
|
+
|
|
101
|
+
1. Integrity `invalid`: `NOT VERIFIED (integrity failed: ...)`.
|
|
102
|
+
2. Any `failed` check: `NOT VERIFIED (failed: <ids>)`. A failed check never yields a passing label.
|
|
103
|
+
3. Record has no facts or no base verdict: `INCOMPLETE (...)`.
|
|
104
|
+
4. Base verdict is not `VERIFIED` or `VERIFIED WITH GAPS`: that verdict, unchanged.
|
|
105
|
+
5. Execution `stale`: `STALE (...)`.
|
|
106
|
+
6. Anything not run, recorded gaps, uncovered requirements, modified tests or unknown freshness: `VERIFIED (scoped: 5 of 7 checks ran; not run: lint, e2e)` with the applicable clauses.
|
|
107
|
+
7. Otherwise `VERIFIED`.
|
|
108
|
+
|
|
109
|
+
The bare word `VERIFIED` therefore means: integrity not failed, no failed checks, every check ran and passed, tree fresh, no uncovered requirements, no modified tests.
|
|
110
|
+
|
|
111
|
+
### Modified tests
|
|
112
|
+
|
|
113
|
+
`modified_tests` lists existing test files the change modified, deleted, renamed or type-changed, derived from `git diff --name-status` between the recorded base and head. Added test files are not listed. Status is `measured` or `unknown` (no base recorded or diff not computable). Modified tests appear in the label and in the summary because an implementer who edits the tests that judge the change weakens the evidence.
|
|
114
|
+
|
|
115
|
+
### Record shape
|
|
116
|
+
|
|
117
|
+
`loki proof show <id> --json` keeps the full proof. The verification record is produced by `proof-verify.py json`, embedded as `verification` in `.loki/verify/evidence.json`, and added as `verification` to the `loki proof verify` JSON. Fields are added, never renamed.
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"schema_version": 1,
|
|
122
|
+
"kind": "proof | evidence",
|
|
123
|
+
"label": "VERIFIED (scoped: ...)",
|
|
124
|
+
"base_verdict": "VERIFIED",
|
|
125
|
+
"integrity": {"status": "valid", "hash_ok": true, "signature": "none", "detail": "..."},
|
|
126
|
+
"execution": {"status": "fresh", "reason": "", "recorded": {}, "current": {}, "environment": {}},
|
|
127
|
+
"requirements": {"status": "recorded", "total": 3, "covered": 1, "uncovered": 2, "uncovered_ids": []},
|
|
128
|
+
"checks": [{"id": "lint", "status": "skipped", "detail": ""}],
|
|
129
|
+
"counts": {"passed": 1, "failed": 0, "skipped": 1, "not_run": 0, "stale": 0, "total": 2, "ran": 1},
|
|
130
|
+
"modified_tests": {"status": "measured", "files": [{"path": "tests/a.py", "change": "modified"}]},
|
|
131
|
+
"complete": true,
|
|
132
|
+
"record_path": ""
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Human output
|
|
137
|
+
|
|
138
|
+
`loki verify` (banner), `loki proof show <id>` and `loki proof verify <id> --human` print a compact summary of about 12 lines: the label, revision and freshness, environment, integrity, check counts with the checks that did not pass, requirement coverage, modified tests, and the signature caveat. Pass `--json` to `loki proof show` for the full record.
|
|
139
|
+
|
|
140
|
+
### Compatibility
|
|
141
|
+
|
|
142
|
+
- Exit codes are unchanged: `loki verify` keeps its verdict-based codes; `loki proof verify` keeps 0 clean, 1 tamper or drift, 2 unusable.
|
|
143
|
+
- Existing JSON fields are untouched. `verification` is additive.
|
|
144
|
+
- Receipts written before this contract lack `facts.environment` and `facts.git.dirty`. They report environment `not recorded` and may report freshness `unknown`.
|
|
145
|
+
- `loki proof show <id>` used to print the raw JSON. Scripts that parsed it must now pass `--json`.
|
|
@@ -115,3 +115,106 @@ mv loki-mode-${VERSION} ~/.claude/skills/loki-mode
|
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
**Best for:** Offline or air-gapped environments, pinned version deployments.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Setup requirements (LM-001)
|
|
122
|
+
|
|
123
|
+
This is the authoritative statement of what Loki Mode needs to run a first task. It is checked by tests against one shared table, `autonomy/lib/setup-requirements.json`. `loki doctor`, `loki doctor --requirements`, `loki doctor --json` (key `requirements`), `loki setup`, and the runtime "provider CLI missing" errors all read that table, so wording and fixes match.
|
|
124
|
+
|
|
125
|
+
Normal repository build dependencies (the toolchain of the project you point Loki at) are not Loki overhead and are not listed.
|
|
126
|
+
|
|
127
|
+
### How to read your machine
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
loki doctor --requirements # per path: ready or not ready, each item required or optional, present or missing, one-line fix
|
|
131
|
+
loki doctor --json # same data under "requirements", plus "first_task_ready"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
A first task is ready when every required "All paths" item is present and at least one execution path is ready. `first_task_ready` in the JSON reports exactly that. It checks presence on this machine; it does not prove that a provider login is valid or that an API key is accepted.
|
|
135
|
+
|
|
136
|
+
### Execution paths
|
|
137
|
+
|
|
138
|
+
- Claude Code CLI path: the default. `loki start` runs the `claude` binary you installed and logged in with `claude auth login`. `loki chat` (with the claude provider) and `loki edit` call the `claude` CLI directly.
|
|
139
|
+
- Anthropic API-key path (Agent SDK, no `claude` CLI): opt-in. It needs `LOKI_SDK_MODE=full` (resolved to `LOKI_SDK_LOOP=1` by `bin/loki`), Anthropic credentials, the bundled `@anthropic-ai/claude-agent-sdk` platform binary, and Bun. It runs only on the Bun route of `loki start`; commands that stay on the bash route (for example `loki demo`, `loki quick`) still need a provider CLI on PATH. Without `LOKI_SDK_MODE=full`, an API key alone does not replace the `claude` CLI for the main loop.
|
|
140
|
+
- Other provider CLIs: `codex` (degraded), `cline`, `aider`, `opencode`. Any one of them replaces the `claude` CLI for `loki start --provider <name>`. Loki never silently substitutes a different provider than the one requested.
|
|
141
|
+
|
|
142
|
+
### Install methods
|
|
143
|
+
|
|
144
|
+
| Install method | What it provides | What you still need |
|
|
145
|
+
| --- | --- | --- |
|
|
146
|
+
| `npm install -g loki-mode` | Loki, a bundled Bun binary and the Claude Agent SDK as npm optional dependencies | Node 20+, python3, jq, git, curl, and one execution path above |
|
|
147
|
+
| `npm install -g loki-mode --omit=optional` (slim) | Loki only; no bundled Bun, no Agent SDK | Everything above, plus Bun from https://bun.sh for the Bun route. Without Bun, `bin/loki` falls back to the bash CLI. The API-key path is unavailable |
|
|
148
|
+
| Homebrew (`brew install loki-mode`) | Loki | Same as npm, and install Bun yourself if you want the Bun route |
|
|
149
|
+
| git clone | Loki sources | Same as npm; see the Git Clone section above for the clone steps |
|
|
150
|
+
|
|
151
|
+
Supported platforms are the `os` entries in `package.json` (darwin, linux).
|
|
152
|
+
|
|
153
|
+
### Requirements by path
|
|
154
|
+
|
|
155
|
+
The tables below are generated from the shared source. Do not edit between the markers; run `UPDATE_CONTRACT=1 bun test tests/commands/doctor.test.ts` from `loki-ts` after editing the JSON, and the test fails if this block drifts.
|
|
156
|
+
|
|
157
|
+
<!-- BEGIN GENERATED REQUIREMENTS (loki-ts/tests/commands/doctor.test.ts) -->
|
|
158
|
+
|
|
159
|
+
### All paths
|
|
160
|
+
|
|
161
|
+
Needed by every Loki command.
|
|
162
|
+
|
|
163
|
+
| Requirement | Level | Check | Fix |
|
|
164
|
+
| --- | --- | --- | --- |
|
|
165
|
+
| Node.js 20 or newer | required | `node` on PATH, version 20.0 or newer | install Node 20+ from https://nodejs.org |
|
|
166
|
+
| Python 3.8 or newer | required | `python3` on PATH, version 3.8 or newer | install python3 with your package manager (brew install python3) |
|
|
167
|
+
| jq | required | `jq` on PATH | install jq with your package manager (brew install jq) |
|
|
168
|
+
| git | required | `git` on PATH | install git with your package manager (brew install git) |
|
|
169
|
+
| curl | required | `curl` on PATH | install curl with your package manager (brew install curl) |
|
|
170
|
+
| bash 4.0 or newer | optional | `bash` on PATH, version 4.0 or newer | install a newer bash (brew install bash); macOS ships 3.2 |
|
|
171
|
+
| Bun 1.3 or newer (bundled by npm install) | optional | `bun` on PATH, version 1.3 or newer | reinstall without --no-optional (npm bundles @oven/bun-*) or install from https://bun.sh; without it loki falls back to the slower bash CLI |
|
|
172
|
+
|
|
173
|
+
### Claude Code CLI path (default, loki start)
|
|
174
|
+
|
|
175
|
+
Loki drives the claude binary you installed and logged in.
|
|
176
|
+
|
|
177
|
+
| Requirement | Level | Check | Fix |
|
|
178
|
+
| --- | --- | --- | --- |
|
|
179
|
+
| claude CLI on PATH (then log in: claude auth login) | required | `claude` on PATH | npm install -g @anthropic-ai/claude-code |
|
|
180
|
+
|
|
181
|
+
### Anthropic API-key path (Agent SDK, no claude CLI)
|
|
182
|
+
|
|
183
|
+
Opt-in with LOKI_SDK_MODE=full; the bundled Agent SDK runs the loop over HTTPS.
|
|
184
|
+
|
|
185
|
+
| Requirement | Level | Check | Fix |
|
|
186
|
+
| --- | --- | --- | --- |
|
|
187
|
+
| SDK loop enabled (LOKI_SDK_MODE=full) | required | `LOKI_SDK_LOOP` is `1` or `true` | export LOKI_SDK_MODE=full |
|
|
188
|
+
| Anthropic credentials (API key, auth token or gateway URL) | required | one of `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_BASE_URL` is set | export ANTHROPIC_API_KEY=<your key> |
|
|
189
|
+
| Claude Agent SDK platform binary (optional npm dependency) | required | executable `@anthropic-ai/claude-agent-sdk-<platform>/claude` in an installed node_modules | reinstall without --no-optional: npm install -g loki-mode (the SDK is an optionalDependency) |
|
|
190
|
+
| Bun runtime (the SDK loop runs only on the Bun route) | required | `bun` on PATH, version 1.3 or newer | reinstall without --no-optional (npm bundles @oven/bun-*) or install from https://bun.sh |
|
|
191
|
+
|
|
192
|
+
### Other provider CLIs
|
|
193
|
+
|
|
194
|
+
codex (degraded), cline, aider, opencode: any one replaces the claude CLI.
|
|
195
|
+
|
|
196
|
+
| Requirement | Level | Check | Fix |
|
|
197
|
+
| --- | --- | --- | --- |
|
|
198
|
+
| codex CLI | optional | `codex` on PATH | npm install -g @openai/codex |
|
|
199
|
+
| cline CLI | optional | `cline` on PATH | npm install -g cline |
|
|
200
|
+
| aider CLI | optional | `aider` on PATH | pip install aider-chat |
|
|
201
|
+
| opencode CLI | optional | `opencode` on PATH | npm install -g opencode-ai |
|
|
202
|
+
|
|
203
|
+
### When an optional dependency is missing
|
|
204
|
+
|
|
205
|
+
| Missing | Effect |
|
|
206
|
+
| --- | --- |
|
|
207
|
+
| @anthropic-ai/claude-agent-sdk (or its platform binary) | The api-key-sdk path is unavailable and doctor reports it not ready. The claude-cli path and all other providers are unaffected. |
|
|
208
|
+
| @oven/bun-* (Bun) | bin/loki falls back to the bash CLI (slower). The api-key-sdk path is unavailable because the SDK loop runs only on Bun. |
|
|
209
|
+
|
|
210
|
+
<!-- END GENERATED REQUIREMENTS -->
|
|
211
|
+
|
|
212
|
+
### Install smoke test
|
|
213
|
+
|
|
214
|
+
`scripts/smoke-install.sh` packs the repository, installs the tarball into a temporary prefix, and runs `loki --version`, `loki doctor --json` and `loki route "add a health endpoint" --json`. It then repeats with Bun and the optional Agent SDK hidden. It is run by hand, is not part of CI, and writes a reproducible log. A run on one machine is evidence for that machine and OS only; it is not an OS matrix.
|
|
215
|
+
|
|
216
|
+
### Known behaviors
|
|
217
|
+
|
|
218
|
+
- Bun-less fallback: when Bun is absent, `loki doctor --json` runs a minimal bash evaluator (`loki_requirements_json` in `autonomy/provider-offer.sh`) over the same table. It checks presence only and does not compare versions, so the Node minimum is enforced only by the Bun doctor.
|
|
219
|
+
- `first_task_ready` does not verify that `claude auth login` was done or that an API key is valid.
|
|
220
|
+
- Observed once, with npm 11.17.0 on macOS arm64 and a local tarball: `npm install -g --omit=optional` still installed `@oven/bun-*` and the Claude Agent SDK packages. The smoke test removes them after install so the second case models a machine without them. This was not checked on other npm versions or from the registry.
|
package/docs/cost-controls.md
CHANGED
|
@@ -41,6 +41,127 @@ while spending almost nothing and completing no iteration, so neither of those
|
|
|
41
41
|
breakers ever trips. The wall-clock cap is the one that catches it. We added it
|
|
42
42
|
after a run burned $34 reaching an external timeout.
|
|
43
43
|
|
|
44
|
+
## Budget contract
|
|
45
|
+
|
|
46
|
+
The per-run spend cap: its default, how it is chosen, what it covers, where it is
|
|
47
|
+
enforced, how far a run can overshoot, what happens when a price is missing, and
|
|
48
|
+
what happens when a run is cancelled. The CLI help, the run-start line and this
|
|
49
|
+
section must agree; tests pin them.
|
|
50
|
+
|
|
51
|
+
### Default
|
|
52
|
+
|
|
53
|
+
The default cap is **100 USD per run**.
|
|
54
|
+
|
|
55
|
+
The number lives in one file, `loki-ts/data/model-pricing.json`
|
|
56
|
+
(`default_max_cost_usd`). Both routes read it:
|
|
57
|
+
|
|
58
|
+
- TypeScript: `loki-ts/src/e10ext/budget_cap.ts` (`DEFAULT_MAX_COST_USD`).
|
|
59
|
+
- Bash: `autonomy/run.sh` (`BUDGET_LIMIT`) and the help text through
|
|
60
|
+
`loki_budget_default_usd` in `autonomy/loki`.
|
|
61
|
+
|
|
62
|
+
`loki-ts/tests/engine10/budget_cap.test.ts` asserts that this document, the JSON
|
|
63
|
+
file, the TypeScript constant, the bash default and the CLI help all state the same
|
|
64
|
+
number. Change the JSON file and the document together.
|
|
65
|
+
|
|
66
|
+
Where the default applies:
|
|
67
|
+
|
|
68
|
+
| Route | Default applies | What the cap does |
|
|
69
|
+
| --- | --- | --- |
|
|
70
|
+
| engine10 (`loki "<task>"`, the Loki 10 engine) | Only when an API key is set (`ANTHROPIC_API_KEY` or `OPENAI_API_KEY`). A subscription run (no key) has no dollar cap. | Ends the run `BUDGET_STOP`, exit 3. |
|
|
71
|
+
| Bash loop (`loki start`, `autonomy/run.sh`) | Always, key or not. | Pauses the run (writes `.loki/PAUSE` and `.loki/signals/BUDGET_EXCEEDED`); remove both to resume. |
|
|
72
|
+
| Bun SDK loop (`LOKI_SDK_LOOP`) | No default. Opt in with `BUDGET_LIMIT`. | Stops the loop when the limit is reached. |
|
|
73
|
+
|
|
74
|
+
The README and the engine guide have shown different figures in the past (100 and
|
|
75
|
+
20). The figure above is the code's, and the two guides follow it.
|
|
76
|
+
|
|
77
|
+
### Precedence
|
|
78
|
+
|
|
79
|
+
Highest first. The first one set wins.
|
|
80
|
+
|
|
81
|
+
1. `--max-cost USD` (engine10) or `--budget USD` (bash route). `loki start --budget`
|
|
82
|
+
is forwarded to engine10 as `--max-cost`.
|
|
83
|
+
2. The environment variable `LOKI_BUDGET_LIMIT`. On the bash route an empty value
|
|
84
|
+
(`LOKI_BUDGET_LIMIT=`) means unlimited.
|
|
85
|
+
3. Config file: `budgets.per_run` in `loki.yaml` (engine10), or the budget setting in
|
|
86
|
+
the settings file loaded by `autonomy/run.sh` (bash route).
|
|
87
|
+
4. The default above (subject to the API-key rule for engine10).
|
|
88
|
+
|
|
89
|
+
### Run-start line
|
|
90
|
+
|
|
91
|
+
Every start prints the active cap and where it came from.
|
|
92
|
+
|
|
93
|
+
- engine10: the start line ends the cap clause with `cap $X.XX (SOURCE)` where SOURCE
|
|
94
|
+
is `--max-cost`, `env`, `loki.yaml` or `default`, or `no dollar cap (subscription)`.
|
|
95
|
+
The default output stays within its 8-line limit.
|
|
96
|
+
- bash route: `Budget limit set: $X.XX (source: flag|env|config|default)`.
|
|
97
|
+
|
|
98
|
+
A cap set through the bash settings file is reported as `config`; the `--config`
|
|
99
|
+
file loader exports the variable, so it reports as `env`.
|
|
100
|
+
|
|
101
|
+
### Scope
|
|
102
|
+
|
|
103
|
+
- **Per run.** The cap covers one run, not a day or a repository.
|
|
104
|
+
- **Retries.** Every session counts, including retried stages and sessions started
|
|
105
|
+
after a provider failover. Each session writes its own cost record, and the run
|
|
106
|
+
total is the sum over every session started, so a retry adds to the total.
|
|
107
|
+
- **Child work.** Subagents and tool calls made inside a provider session are part of
|
|
108
|
+
that session's reported cost. Sessions run in a temporary directory (the Wall stage)
|
|
109
|
+
have their cost record copied into the run before the directory is removed.
|
|
110
|
+
- **Not counted.** The detached deep verify that may start after a PR opens is a
|
|
111
|
+
separate process and is not counted against the run cap. Sessions with no known
|
|
112
|
+
price are not counted either (see "Missing prices").
|
|
113
|
+
|
|
114
|
+
### Enforcement point and overshoot
|
|
115
|
+
|
|
116
|
+
engine10 checks the cap before each stage starts (`machine.ts`, `capReached`), using
|
|
117
|
+
the cost events recorded so far. A stage that is already running is not interrupted by
|
|
118
|
+
the dollar cap. The documented overshoot is therefore up to the cost of the stages in
|
|
119
|
+
flight when the cap is crossed (the plan and wall stages can run together). Time caps
|
|
120
|
+
and the per-session time limit still apply inside a stage.
|
|
121
|
+
|
|
122
|
+
The bash route checks after each iteration (`check_budget_limit`), so the overshoot is
|
|
123
|
+
up to one iteration.
|
|
124
|
+
|
|
125
|
+
### Missing prices
|
|
126
|
+
|
|
127
|
+
Cost is never reported as 0 when it was not measured.
|
|
128
|
+
|
|
129
|
+
- A session with no dollar figure records `usd: null` in its cost event. Token counts
|
|
130
|
+
are kept when the provider reported them.
|
|
131
|
+
- A model with no entry in the price table (`loki-ts/src/providers/price_table.ts`)
|
|
132
|
+
is not priced with a default guess. The cost record carries `total_cost_usd: null`,
|
|
133
|
+
`cost_basis: "unpriced"` and an `unmeasured_reason` naming the model.
|
|
134
|
+
- The bash iteration record omits `cost_usd` and writes `cost_unmeasured_reason`
|
|
135
|
+
instead of `"cost_usd": 0`.
|
|
136
|
+
- Unmeasured sessions never count toward the cap, so a run with unpriced models is not
|
|
137
|
+
stopped by a guess. The run summary says `not measured`, or `partial: $X for N of M
|
|
138
|
+
sessions` when only some sessions were priced. It never prints `$0.00` for a run
|
|
139
|
+
whose cost is unknown. The cap is only as good as the prices behind it: a run on a
|
|
140
|
+
model the table does not know is effectively uncapped, and the summary says so.
|
|
141
|
+
|
|
142
|
+
### Cancellation
|
|
143
|
+
|
|
144
|
+
SIGINT or SIGTERM during an engine10 run:
|
|
145
|
+
|
|
146
|
+
1. The supervisor forwards SIGTERM to the worker process group and keeps reading its
|
|
147
|
+
output.
|
|
148
|
+
2. The worker stops every live provider session. All providers share one spawn path
|
|
149
|
+
(`createSessionRunner`), so one rule covers them all: SIGTERM to the session's
|
|
150
|
+
process group, then SIGKILL after 2 seconds. No new session starts.
|
|
151
|
+
3. Each stopped session records the usage measured so far, with its unmeasured flag
|
|
152
|
+
when no dollar figure exists (`usd: null`).
|
|
153
|
+
4. If the worker has not exited after the cancel grace (10 seconds, set with
|
|
154
|
+
`LOKI_E10_CANCEL_GRACE_MS`), the supervisor SIGKILLs the group. A second signal
|
|
155
|
+
escalates immediately.
|
|
156
|
+
5. The supervisor opens no PR and makes no backstop commit, restores the branch the
|
|
157
|
+
run started on, and appends `run.completed` with `cancelled: true`,
|
|
158
|
+
`outcome: "CANCELLED"` and the cost folded from the events. `loki status` shows the
|
|
159
|
+
run as `cancelled`, distinct from `FAILED`.
|
|
160
|
+
6. The run summary is printed with `Outcome: CANCELLED` and the process exits **130**.
|
|
161
|
+
|
|
162
|
+
The test `loki-ts/tests/engine10/supervisor_signal.test.ts` drives this with a stub
|
|
163
|
+
provider that sleeps.
|
|
164
|
+
|
|
44
165
|
## Hitting a cap is a FAILURE, not a success
|
|
45
166
|
|
|
46
167
|
This is the part that matters for anyone automating against us.
|
|
@@ -86,3 +207,21 @@ What we do instead:
|
|
|
86
207
|
|
|
87
208
|
If a run cost more than you expected, `loki proof show <id>` tells you where it
|
|
88
209
|
went.
|
|
210
|
+
|
|
211
|
+
## Backend capability contract (LM-004)
|
|
212
|
+
|
|
213
|
+
One table in `loki-ts/src/providers/provider_guard.ts` (`CAPABILITIES`) records what each provider guarantees on engine10. `loki provider matrix` prints it (all engines), `loki provider info <name> --json` prints one provider's rows with the source files each value was read from, and `loki start` prints one disclosure line before the run when the provider falls short of Claude. Claude prints nothing extra. On the legacy bash engine only the invocation and sandbox flags are confirmed from code; every other value there is `unknown`, which means not confirmed, not absent.
|
|
214
|
+
|
|
215
|
+
- cost: `measured` = provider-reported; `estimated` = parsed or size-based and flagged estimated; `none` = reported as not measured.
|
|
216
|
+
- budget kill: `post-iteration` = no further stage starts once priced cost reaches the cap; `none` = no cap applies.
|
|
217
|
+
- cancel (pgroup): the session child is killed as a whole process group.
|
|
218
|
+
- guard scan: `native` = the provider's own hooks gate each call; `post-iteration` = diff scan after each iteration, reverting destructive changes.
|
|
219
|
+
- kill blocking: `native` = enforced; `none` = receipts list `kill blocking not enforced`.
|
|
220
|
+
|
|
221
|
+
| provider | engine | cost | budget kill | cancel (pgroup) | sandbox flags | receipt | resume | guard scan | kill blocking |
|
|
222
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
223
|
+
| claude | engine10 | measured | post-iteration | yes | none | yes | yes | native | native |
|
|
224
|
+
| codex | engine10 | estimated | post-iteration | yes | --sandbox workspace-write | yes | no | post-iteration | none |
|
|
225
|
+
| cline | engine10 | estimated | post-iteration | yes | none | yes | no | post-iteration | none |
|
|
226
|
+
| aider | engine10 | estimated | post-iteration | yes | --no-auto-commits | yes | no | post-iteration | none |
|
|
227
|
+
| opencode | engine10 | none | none | yes | none | yes | no | post-iteration | none |
|
|
@@ -49,6 +49,7 @@ interact and why hitting one is a failure rather than a success.
|
|
|
49
49
|
| `LOKI_ENGINE` | unset | `legacy` forces the previous loop; the `--engine` flag wins over it. |
|
|
50
50
|
| `LOKI_SUMMARY_JSON` | unset | `1` prints the end-of-run summary as one JSON line on the previous loop. |
|
|
51
51
|
| `LOKI_TIER` | `oss` | **Not a model setting.** The open-core licensing seam. Leave it unset. |
|
|
52
|
+
| `LOKI_REPO_BASELINE` | unset | `0` skips the intake repo profile and baseline test run (see docs/HARNESS-INTELLIGENCE-PLAN.md). |
|
|
52
53
|
| `LOKI_ALLOW_CLAUDE_SIDECALLS` | unset | `1` (exactly) lets PRD enrichment, done recognition, the council voters, the USAGE.md refresh and the quickstart intent check prompt the `claude` CLI under a non-claude provider; `loki doctor --airgap` then reports that as required egress to Anthropic. |
|
|
53
54
|
|
|
54
55
|
### Picking a model without naming one
|
|
@@ -99,11 +100,46 @@ behaviour has a switch rather than a fork.
|
|
|
99
100
|
| `LOKI_INJECT_FINDINGS` | on | Injects the previous iteration's reviewer findings, by severity and file:line. `0` makes the next iteration a blind retry. |
|
|
100
101
|
| `LOKI_ITERATION_GRACE` | on | When the agent reports done and no gate is failing, grants ONE extra iteration past the cap to land the work. Granted at most once per run. `0` restores a pure counter. |
|
|
101
102
|
| `LOKI_SCOPED_CHANGE` | auto | Forces the scoped-change profile on (`1`) or off (`0`). Auto-detected from an issue-sourced spec on a repository with real history. Never disables a trust gate; it skips phases irrelevant to a scoped fix. |
|
|
103
|
+
| `LOKI_RISK_TIER` | computed | Raises the verification tier (`low`, `medium`, `high`) above the one computed from the diff. Lowering is ignored unless `LOKI_RISK_OVERRIDE_REASON` is also set. |
|
|
104
|
+
| `LOKI_RISK_OVERRIDE_REASON` | unset | Recorded reason that lets `LOKI_RISK_TIER` lower the computed tier. Stored in the risk record and shown in the run summary. |
|
|
102
105
|
|
|
103
106
|
`LOKI_INJECT_FINDINGS=0` is the one to think twice about. Without it the model
|
|
104
107
|
is told to fix problems without being told which, so it re-derives them from
|
|
105
108
|
scratch every iteration -- the slowest and least accurate way to converge.
|
|
106
109
|
|
|
110
|
+
### Verification depth (risk tier)
|
|
111
|
+
|
|
112
|
+
The v10 verify stage classifies risk on the diff (the artifact), never on the
|
|
113
|
+
prompt, and records the result in `.loki/state/risk-tier.json`. The run
|
|
114
|
+
summary prints its one-line `summary` (also `summary.risk` under `--json`; in
|
|
115
|
+
default output only while the 8-line cap still holds). A record older than the
|
|
116
|
+
run start is ignored, and a classification failure never fails verify.
|
|
117
|
+
`loki review --risk` (`autonomy/lib/review_risk.py`) is a separate 0-100
|
|
118
|
+
advisory score and is unchanged.
|
|
119
|
+
|
|
120
|
+
- high: a sensitive path (auth, crypto, payments, migrations or `.sql`, CI config, lockfiles, infra, `.env`), a deleted test file, public API surface (openapi/swagger, `.proto`, `.d.ts`, `api/`, `routes/`, `public/`, index files), 15+ files, or 500+ changed lines.
|
|
121
|
+
- medium: an existing test or test config modified, 4+ files, or 100+ changed lines.
|
|
122
|
+
- low: everything else. Test files are never counted as sensitive.
|
|
123
|
+
|
|
124
|
+
| Tier | Selected checks | Recorded as not run |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| low | targeted tests, lint of changed files | full test command, reviewer, council, security scan (skipped by design) |
|
|
127
|
+
| medium | low plus full test command, one reviewer | one reviewer (and the full test command when no runner was detected) |
|
|
128
|
+
| high | medium plus full suite, council, security scan | council, security scan (and the full test command and full suite when no runner was detected) |
|
|
129
|
+
|
|
130
|
+
Targeted tests and lint always run. At medium and high, verify also runs the
|
|
131
|
+
detected full test command (the `deep.ts` per-runner table); a full-test
|
|
132
|
+
failure counts like any failing check, and a `not_run` result is added to
|
|
133
|
+
`not_proven`. Reviewer, council and security scan are not run by fast verify at
|
|
134
|
+
any tier, so they stay recorded as not run; nothing marks a skipped check as
|
|
135
|
+
passing. Record shape: `{version, tier, computed, reasons[], stats{files, lines,
|
|
136
|
+
sensitive[], tests_modified[], tests_deleted[], api[]}, checks_selected[],
|
|
137
|
+
checks_deferred[], override?, override_ignored?, summary}`.
|
|
138
|
+
|
|
139
|
+
Known gaps: the bash `run.sh` council triggers and the outcome record do not
|
|
140
|
+
yet use this tier; public API detection is path-based, not a semantic diff of
|
|
141
|
+
exports; a full-test failure that also fails on the base is not subtracted.
|
|
142
|
+
|
|
107
143
|
## Timeouts
|
|
108
144
|
|
|
109
145
|
| Variable | Default | Effect |
|
package/docs/exit-codes.md
CHANGED
|
@@ -24,7 +24,9 @@ is the part most likely to surprise a script author.
|
|
|
24
24
|
|
|
25
25
|
Usage errors are distinct from run outcomes: `loki start` with an unknown
|
|
26
26
|
option exits 64, and `loki quick` with no task description exits 64 (they were
|
|
27
|
-
1 and 2). A missing provider CLI still exits 2 before any spend
|
|
27
|
+
1 and 2). A missing provider CLI still exits 2 before any spend, and so does a
|
|
28
|
+
working directory that is not a git repository (`engine10: not inside a git
|
|
29
|
+
repository`). A PRD path that does not exist also exits 2 (`PRD file not found`). There is no
|
|
28
30
|
finer run-outcome signal. A gate that needs to tell "failed the quality gate"
|
|
29
31
|
from "crashed" must opt into the durable contract below.
|
|
30
32
|
|
|
@@ -59,7 +61,8 @@ identically; a parity test asserts they agree status for status.
|
|
|
59
61
|
|---|---|
|
|
60
62
|
| 0 | The run completed and its diff did not weaken the tests |
|
|
61
63
|
| 3 | The diff weakened the tests (a skip marker added in a test file, a test runner config changed, or an existing test file deleted or renamed). The receipt headline is NOT VERIFIED and names what was weakened, for example `NOT VERIFIED (tests weakened: skip added in sum.test.js)` |
|
|
62
|
-
|
|
|
64
|
+
| 2 | Not a git repository (engine10 preflight, before any spend), or a missing provider CLI |
|
|
65
|
+
| 64 | Usage error: no task description, or an unknown leading `--option` (from 11.5.0; before that it was taken as task text and started a paid run) |
|
|
63
66
|
| other nonzero | The run itself failed; this code is passed through unchanged |
|
|
64
67
|
|
|
65
68
|
`loki quick` has no `--json` flag; its structured result is `loki why --json`, schema: `schemas/why-result.schema.json` (`state.lastExitCode` carries the ladder above).
|
|
@@ -363,3 +366,100 @@ One provider pass, no loop.
|
|
|
363
366
|
| 0 | Edit done (or nothing to change, or `--dry-run` plan printed) |
|
|
364
367
|
| 1 | Provider pass failed, or `--verify` failed (nothing is committed) |
|
|
365
368
|
| 2 | Usage or setup error (no change text, not a git repo, claude or python3 missing, unsupported provider) |
|
|
369
|
+
|
|
370
|
+
## `loki run` (deprecated alias of `loki start <issue-ref>`)
|
|
371
|
+
|
|
372
|
+
Not changed. `loki run` with an unknown option exits 1 (it predates the 64 usage
|
|
373
|
+
contract and keeps its code); with no issue reference it exits 2. New scripts
|
|
374
|
+
should call `loki start` instead. `loki route` input errors (a missing PRD file,
|
|
375
|
+
or `--engine engine10` combined with a flag engine10 cannot honor) exit 2.
|
|
376
|
+
|
|
377
|
+
## Contract cases
|
|
378
|
+
|
|
379
|
+
Each row is executed against the real CLI by `tests/test-exit-codes-documented.sh`,
|
|
380
|
+
which fails if an observed code differs from the Exit column. Every case stops
|
|
381
|
+
before any provider spend. An empty diff is a distinct code only for `loki verify`
|
|
382
|
+
(3). `loki edit` treats it as "nothing to change" (exit 0, see above); `loki quick`,
|
|
383
|
+
`loki start` and `loki run` have no empty-diff exit code, and none is asserted.
|
|
384
|
+
|
|
385
|
+
| Case | Command and setup | Exit | Meaning |
|
|
386
|
+
|---|---|---|---|
|
|
387
|
+
| `verify-empty-diff` | `loki verify` in a repo with no diff vs base | 3 | Verifier error: nothing to check is never a pass |
|
|
388
|
+
| `verify-not-git` | `loki verify` outside a git repository | 2 | Could not check |
|
|
389
|
+
| `verify-unknown-flag` | `loki verify --no-such-flag` | 64 | Usage error |
|
|
390
|
+
| `run-unknown-flag` | `loki run --no-such-flag` | 1 | Legacy alias keeps its pre-64 code |
|
|
391
|
+
| `run-no-issue-ref` | `loki run` with no argument | 2 | Issue reference required |
|
|
392
|
+
| `quick-unknown-flag` | `loki quick --no-such-flag` | 64 | Usage error (from 11.5.0) |
|
|
393
|
+
| `quick-no-task` | `loki quick` with no argument | 64 | Usage error |
|
|
394
|
+
| `quick-not-git` | `loki quick fix the bug now` outside a git repository | 2 | engine10 preflight, before spend |
|
|
395
|
+
| `edit-unknown-flag` | `loki edit --no-such-flag` | 2 | Usage error |
|
|
396
|
+
| `edit-no-change` | `loki edit` with no change text | 2 | Usage error |
|
|
397
|
+
| `edit-not-git` | `loki edit "change x"` outside a git repository | 2 | Setup error |
|
|
398
|
+
| `start-unknown-flag` | `loki start --no-such-flag` | 64 | Usage error |
|
|
399
|
+
| `start-missing-prd` | `loki start missing-prd.md` | 2 | PRD file not found |
|
|
400
|
+
| `start-not-git` | `loki start fix the bug now` outside a git repository | 2 | engine10 preflight, before spend |
|
|
401
|
+
|
|
402
|
+
Migration note (11.5.0): `loki quick --some-typo` used to run a paid task whose text
|
|
403
|
+
was the flag. It now exits 64 before any spend. Task text that starts with `--` must
|
|
404
|
+
be rephrased or put after other words.
|
|
405
|
+
|
|
406
|
+
## Routing contract
|
|
407
|
+
|
|
408
|
+
Authoritative contract for which engine and adapter `loki start` and `loki quick` use for each input form. Inspect any call without running it:
|
|
409
|
+
|
|
410
|
+
```sh
|
|
411
|
+
loki route start <args> --json
|
|
412
|
+
loki route quick <args> --json
|
|
413
|
+
loki --explain-route <flag-first args>
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
The JSON carries `engine`, `adapter`, `provider`, `model`, `input_type`, `input`, `reason` and `capability_differences`. `capability_differences` is an empty list only for the full Claude Code path on the Loki 10 engine. Any compatibility route (the legacy bash loop, or a provider other than Claude) lists at least one difference.
|
|
417
|
+
|
|
418
|
+
### Rules
|
|
419
|
+
|
|
420
|
+
- Argument order never changes the route: flags first or last, `--prd FILE` or a positional file, `--provider X` or `LOKI_PROVIDER=X`, `--engine X` or `LOKI_ENGINE=X` all resolve identically (the flag wins over the env var).
|
|
421
|
+
- Default engine is `engine10` for a PRD file (`.md`, `.json`, `.yaml`), an issue reference (`owner/repo#N` or an issue URL), a multi-word task and a one-word brief.
|
|
422
|
+
- The legacy engine runs only on `--engine legacy` or `LOKI_ENGINE=legacy`, for one call when a flag engine10 does not support is present (a notice is printed), for a provider with no engine10 invoker, or for a PRD larger than 100000 bytes.
|
|
423
|
+
- `--engine engine10` with an unsupported flag is refused (exit 2) instead of rerouted.
|
|
424
|
+
- A missing PRD file path is a usage error (exit 2).
|
|
425
|
+
- Adapter is `<engine>:<provider>`, with the legacy engine written `legacy-bash:<provider>`.
|
|
426
|
+
- Claude Code is the primary provider. The `loki chat` surface does not use this router; it is a separate interactive entry point.
|
|
427
|
+
|
|
428
|
+
### Invocation table
|
|
429
|
+
|
|
430
|
+
The table below is rendered from live `loki route --json` output by `tests/test-engine10-dispatch.sh`. The test fails if it drifts; regenerate with `bash tests/test-engine10-dispatch.sh --update-doc`.
|
|
431
|
+
|
|
432
|
+
<!-- route-table:begin (generated by tests/test-engine10-dispatch.sh --update-doc) -->
|
|
433
|
+
| Invocation (after `loki route`, unless it starts with `loki` or an env var) | Engine | Adapter | Capability differences | Reason |
|
|
434
|
+
|---|---|---|---|---|
|
|
435
|
+
| `start p.md` | engine10 | engine10:claude | none | default: prd input runs on engine10 regardless of flag order |
|
|
436
|
+
| `start p.md --provider claude` | engine10 | engine10:claude | none | default: prd input runs on engine10 regardless of flag order |
|
|
437
|
+
| `start --provider claude p.md` | engine10 | engine10:claude | none | default: prd input runs on engine10 regardless of flag order |
|
|
438
|
+
| `start --prd p.md` | engine10 | engine10:claude | none | default: prd input runs on engine10 regardless of flag order |
|
|
439
|
+
| `start p.json` | engine10 | engine10:claude | none | default: prd input runs on engine10 regardless of flag order |
|
|
440
|
+
| `start p.yaml` | engine10 | engine10:claude | none | default: prd input runs on engine10 regardless of flag order |
|
|
441
|
+
| `start "fix the bug"` | engine10 | engine10:claude | none | default: task input runs on engine10 regardless of flag order |
|
|
442
|
+
| `start fix the bug` | engine10 | engine10:claude | none | default: task input runs on engine10 regardless of flag order |
|
|
443
|
+
| `loki --explain-route --json "fix the bug"` | engine10 | engine10:claude | none | default: task input runs on engine10 regardless of flag order |
|
|
444
|
+
| `quick "fix the bug"` | engine10 | engine10:claude | none | default: task input runs on engine10 regardless of flag order |
|
|
445
|
+
| `quick fix the bug` | engine10 | engine10:claude | none | default: task input runs on engine10 regardless of flag order |
|
|
446
|
+
| `start owner/repo#5` | engine10 | engine10:claude | none | default: issue input runs on engine10 regardless of flag order |
|
|
447
|
+
| `start owner/repo#5 --provider claude` | engine10 | engine10:claude | none | default: issue input runs on engine10 regardless of flag order |
|
|
448
|
+
| `start https://github.com/owner/repo/issues/5` | engine10 | engine10:claude | none | default: issue input runs on engine10 regardless of flag order |
|
|
449
|
+
| `start hello` | engine10 | engine10:claude | none | default: brief input runs on engine10 regardless of flag order |
|
|
450
|
+
| `start p.md --provider codex` | engine10 | engine10:codex | 1 listed | default: prd input runs on engine10 regardless of flag order |
|
|
451
|
+
| `start --provider codex p.md` | engine10 | engine10:codex | 1 listed | default: prd input runs on engine10 regardless of flag order |
|
|
452
|
+
| `LOKI_PROVIDER=codex start p.md` | engine10 | engine10:codex | 1 listed | default: prd input runs on engine10 regardless of flag order |
|
|
453
|
+
| `start p.md --provider cline` | engine10 | engine10:cline | 1 listed | default: prd input runs on engine10 regardless of flag order |
|
|
454
|
+
| `start p.md --provider aider` | engine10 | engine10:aider | 1 listed | default: prd input runs on engine10 regardless of flag order |
|
|
455
|
+
| `start p.md --provider opencode` | engine10 | engine10:opencode | 1 listed | default: prd input runs on engine10 regardless of flag order |
|
|
456
|
+
| `start p.md --provider gemini` | legacy | legacy-bash:gemini | 2 listed | provider gemini has no engine10 invoker (use claude, codex, cline, aider or opencode) |
|
|
457
|
+
| `start p.md --engine legacy` | legacy | legacy-bash:claude | 1 listed | explicit: --engine legacy or LOKI_ENGINE=legacy |
|
|
458
|
+
| `start --engine legacy p.md` | legacy | legacy-bash:claude | 1 listed | explicit: --engine legacy or LOKI_ENGINE=legacy |
|
|
459
|
+
| `LOKI_ENGINE=legacy start p.md` | legacy | legacy-bash:claude | 1 listed | explicit: --engine legacy or LOKI_ENGINE=legacy |
|
|
460
|
+
| `start p.md --engine engine10` | engine10 | engine10:claude | none | explicit: --engine engine10 |
|
|
461
|
+
| `LOKI_ENGINE=engine10 start p.md` | engine10 | engine10:claude | none | explicit: --engine engine10 |
|
|
462
|
+
| `start p.md --parallel` | legacy | legacy-bash:claude | 2 listed | flag --parallel is not supported by engine10 |
|
|
463
|
+
| `start --parallel p.md` | legacy | legacy-bash:claude | 2 listed | flag --parallel is not supported by engine10 |
|
|
464
|
+
| `start big.md` | legacy | legacy-bash:claude | 1 listed | PRD is larger than 100000 bytes (engine10 takes the task as one argument) |
|
|
465
|
+
<!-- route-table:end -->
|
|
@@ -26,3 +26,32 @@ A spec that does not parse exits 2 before any run state is created, naming the f
|
|
|
26
26
|
## Unchanged without the flags
|
|
27
27
|
|
|
28
28
|
Without `--spec` or `--spec-first`, `loki plan` stays on its existing route, `loki start` behaves as before, and the plan and implement briefs are byte-identical (pinned by golden fixtures in `loki-ts/tests/engine10/fixtures`).
|
|
29
|
+
|
|
30
|
+
## Requirement-to-check map (REQTRACE)
|
|
31
|
+
|
|
32
|
+
File: `.loki/state/requirements-map.json`. Written after verification, before the run summary. Read-only view: `loki plan --requirements` (add `--json` for the raw file). Code: `loki-ts/src/features/contract.ts`; tests: `loki-ts/tests/features/contract.test.ts`.
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{"version":1,"revision":"<git sha at write time, or \"unknown\">","requirements":[
|
|
36
|
+
{"id":"R1","text":"...","checks":["<check id>"],"status":"covered","method":"explicit"}
|
|
37
|
+
]}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- `status` is `covered` only when at least one check that actually ran and passed maps to the requirement. `checks` lists only those passing checks. A failed, flaky, not_run or pending check never covers.
|
|
41
|
+
- `method` is `explicit` when the requirement carries its own link to checks, `heuristic` otherwise. An uncovered requirement with no link is `heuristic` with `checks: []`.
|
|
42
|
+
- Ids `R1..Rn` are assigned in source order. At most 40 requirements are taken from PRD text.
|
|
43
|
+
- The file is never written when there is no requirement source, and a write failure never fails a run.
|
|
44
|
+
|
|
45
|
+
Requirements and checks come from existing extractors, with no second parser:
|
|
46
|
+
|
|
47
|
+
| Run | Requirements | Checks that ran | Link |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| Bun runner (`loki start`, default) | `.loki/checklist/checklist.json` items | that item's `verification[]` entries, id `<item id>:<type>:<n>`; `passed === true` counts | explicit, by construction |
|
|
50
|
+
| engine10 with `--spec` | acceptance criteria of the spec snapshot (`spec_file.ts` parseSpec) | `test.result` events of the run, id = check name (`runner:path`) | explicit if the criterion ends with `[check: id1, id2]`, else heuristic |
|
|
51
|
+
| engine10 text or PRD task | units from `autonomy/lib/requirements_contract.py` `extract_bound_requirement_units`; needs 2 or more units | same `test.result` events | heuristic |
|
|
52
|
+
|
|
53
|
+
Heuristic rule: a passing check matches when it shares at least 2 significant words (4 or more letters, minus a small stop list; all of them when the requirement has only one) with the check id plus command. It is a hint, not proof, which is why `method` is recorded.
|
|
54
|
+
|
|
55
|
+
Surfaces: the run summary next-step line reads `N requirement(s) uncovered, see: loki plan --requirements` when `N > 0`, inside the 8-line cap (engine10 `withNextLine` / `formatRunSummary`, and `autonomy/lib/run-summary.sh` for the bash summary). The JSON summary adds `requirements_uncovered` only when `N > 0`.
|
|
56
|
+
|
|
57
|
+
Known gaps: the legacy bash engine (`autonomy/run.sh` without Bun) does not write the map; its summary only reads one if present. Heuristic matching is word overlap only and can both miss and over-claim, so use explicit `[check: id]` links for requirements that matter.
|
package/docs/v10/CLI-MODERN.md
CHANGED
|
@@ -11,7 +11,7 @@ Classes: KEEP-MODERN (v10-native or engine-neutral), UPDATE (live but needs mode
|
|
|
11
11
|
- DROP-LEGACY: 32
|
|
12
12
|
- DELETE: 14
|
|
13
13
|
- Total rows: 137
|
|
14
|
-
- Registry paths (commands and nested subcommands):
|
|
14
|
+
- Registry paths (commands and nested subcommands): 190
|
|
15
15
|
|
|
16
16
|
## Commands
|
|
17
17
|
|
|
@@ -184,7 +184,7 @@ Classes: KEEP-MODERN (v10-native or engine-neutral), UPDATE (live but needs mode
|
|
|
184
184
|
- preview: 1
|
|
185
185
|
- projects: 8
|
|
186
186
|
- proof: 6
|
|
187
|
-
- provider:
|
|
187
|
+
- provider: 2
|
|
188
188
|
- quick: 1
|
|
189
189
|
- resume: 1
|
|
190
190
|
- rollback: 2
|