loki-mode 8.5.2 → 8.6.0
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/README.md +16 -0
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +225 -6
- package/autonomy/run.sh +106 -9
- package/autonomy/telemetry.sh +45 -0
- package/autonomy/verify.sh +85 -19
- package/completions/_loki +1 -0
- package/completions/loki.bash +1 -1
- package/dashboard/__init__.py +1 -1
- package/docs/EVALUATING.md +28 -0
- package/docs/PRIVACY.md +25 -2
- package/docs/air-gapped.md +91 -0
- package/docs/brownfield.md +120 -0
- package/docs/cost-controls.md +88 -0
- package/docs/environment-variables.md +102 -0
- package/docs/exit-codes.md +130 -0
- package/docs/image-provenance.md +124 -0
- package/loki-ts/dist/loki.js +288 -284
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
package/autonomy/verify.sh
CHANGED
|
@@ -39,12 +39,23 @@
|
|
|
39
39
|
# 2 BLOCKED
|
|
40
40
|
# 3 verifier error (could not complete; never silently passes)
|
|
41
41
|
#
|
|
42
|
-
#
|
|
43
|
-
# 0=VERIFIED, 1=BLOCKED, 2=CONCERNS,
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
42
|
+
# EXIT-CODE ORDERING, RECONCILED. An early draft spec listed
|
|
43
|
+
# 0=VERIFIED, 1=BLOCKED, 2=CONCERNS, and this header used to say a human must
|
|
44
|
+
# reconcile the two before the GitHub App consumed exit codes. That is now
|
|
45
|
+
# done, in favor of THIS implementation: 0/1/2/3 =
|
|
46
|
+
# VERIFIED/CONCERNS/BLOCKED/error.
|
|
47
|
+
#
|
|
48
|
+
# Why this ordering wins. The code is authoritative and always has been
|
|
49
|
+
# (VERIFY_EXIT_* below), `loki verify --help` documents it, and
|
|
50
|
+
# wiki/CLI-Reference.md documents it. The draft spec that said otherwise is not
|
|
51
|
+
# in this repository and has no consumers. Renumbering working code to match an
|
|
52
|
+
# absent document would break every existing caller to satisfy nothing.
|
|
53
|
+
#
|
|
54
|
+
# It is also the ordering an integrator expects: severity rises with the code,
|
|
55
|
+
# so `[ $rc -ge 2 ]` means "at least blocked". The reverse would make 1 more
|
|
56
|
+
# severe than 2, which no one guesses correctly.
|
|
57
|
+
#
|
|
58
|
+
# See docs/exit-codes.md for the exit codes of every command.
|
|
48
59
|
|
|
49
60
|
set -uo pipefail
|
|
50
61
|
|
|
@@ -1810,6 +1821,7 @@ verify_emit_evidence() {
|
|
|
1810
1821
|
_VERIFY_GATES="$_VERIFY_GATES_FILE" \
|
|
1811
1822
|
_V_VERDICT="$VERIFY_VERDICT" \
|
|
1812
1823
|
_V_EXIT="$VERIFY_EXIT" \
|
|
1824
|
+
_V_JSON_STDOUT="${VERIFY_JSON:-0}" \
|
|
1813
1825
|
_V_SCHEMA="$VERIFY_SCHEMA_VERSION" \
|
|
1814
1826
|
_V_TOOLVER="$tool_version" \
|
|
1815
1827
|
_V_REPO="$repo_name" \
|
|
@@ -1833,7 +1845,7 @@ verify_emit_evidence() {
|
|
|
1833
1845
|
_V_SCOPE_MAX_FILES="${VERIFY_SCOPE_MAX_FILES:-}" \
|
|
1834
1846
|
_V_SCOPE_MAX_NET="${VERIFY_SCOPE_MAX_NET_LINES:-}" \
|
|
1835
1847
|
python3 - <<'PYEOF'
|
|
1836
|
-
import json, os, hashlib
|
|
1848
|
+
import json, os, hashlib, sys
|
|
1837
1849
|
|
|
1838
1850
|
out_dir = os.environ["_VERIFY_OUT_DIR"]
|
|
1839
1851
|
findings_file = os.environ["_VERIFY_FINDINGS"]
|
|
@@ -1959,6 +1971,27 @@ with open(ev_path, "w") as f:
|
|
|
1959
1971
|
json.dump(doc, f, indent=2)
|
|
1960
1972
|
f.write("\n")
|
|
1961
1973
|
|
|
1974
|
+
# --json emits the SAME document to stdout. Deliberately the same `doc` rather
|
|
1975
|
+
# than a second serializer: two writers of one contract drift, and the drift
|
|
1976
|
+
# shows up as a caller trusting a field the file no longer has. The evidence
|
|
1977
|
+
# file is still written either way, so --json adds a pipe without removing the
|
|
1978
|
+
# artifact.
|
|
1979
|
+
#
|
|
1980
|
+
# Written to FD 3, not stdout. The caller redirects this function's stdout to
|
|
1981
|
+
# /dev/null (it emits progress chatter the human path does not want), so a
|
|
1982
|
+
# plain stdout write here is discarded. FD 3 is opened by the caller only under
|
|
1983
|
+
# --json and routed to the real stdout.
|
|
1984
|
+
if os.environ.get("_V_JSON_STDOUT") == "1":
|
|
1985
|
+
try:
|
|
1986
|
+
with os.fdopen(os.dup(3), "w") as _jf:
|
|
1987
|
+
_jf.write(json.dumps(doc, indent=2) + "\n")
|
|
1988
|
+
except OSError:
|
|
1989
|
+
# FD 3 not open: --json was requested but the caller did not wire it.
|
|
1990
|
+
# Fail loudly rather than exit 0 having emitted nothing, which would
|
|
1991
|
+
# look to a pipeline like a verify that produced an empty document.
|
|
1992
|
+
sys.stderr.write("verify: --json requested but FD 3 is not open\n")
|
|
1993
|
+
raise SystemExit(3)
|
|
1994
|
+
|
|
1962
1995
|
# ----- Markdown report -----
|
|
1963
1996
|
def sev_rank(s):
|
|
1964
1997
|
return {"Critical": 0, "High": 1, "Medium": 2, "Low": 3, "Info": 4}.get(s, 5)
|
|
@@ -2050,6 +2083,11 @@ OPTIONS:
|
|
|
2050
2083
|
Default: critical,high (one notch looser than the
|
|
2051
2084
|
Loki build loop, which also blocks on medium).
|
|
2052
2085
|
--no-llm Accepted for forward-compat; LLM is already off in MVP.
|
|
2086
|
+
--json Emit the evidence document to stdout so it can be piped
|
|
2087
|
+
(`loki verify --json | jq .verdict`). The same document
|
|
2088
|
+
is still written to <out>/evidence.json. The human
|
|
2089
|
+
VERDICT banner moves to stderr so stdout stays valid
|
|
2090
|
+
JSON. The verdict and exit code are unchanged.
|
|
2053
2091
|
--explain Print a one-screen, skeptic-legible trust proof: every
|
|
2054
2092
|
gate that ran, its status, the runner/scanner that
|
|
2055
2093
|
produced the evidence, whether it is reproducible, plus
|
|
@@ -2093,16 +2131,16 @@ VERDICT MODEL:
|
|
|
2093
2131
|
Uncommitted working-tree changes are not verified; commit them first. An
|
|
2094
2132
|
empty diff yields CONCERNS (nothing to verify), never VERIFIED.
|
|
2095
2133
|
|
|
2096
|
-
EXIT CODES
|
|
2134
|
+
EXIT CODES:
|
|
2097
2135
|
0 VERIFIED
|
|
2098
2136
|
1 CONCERNS
|
|
2099
2137
|
2 BLOCKED
|
|
2100
2138
|
3 verifier error (could not complete; never silently passes)
|
|
2101
2139
|
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2140
|
+
Severity rises with the code, so `[ $rc -ge 2 ]` means "at least blocked".
|
|
2141
|
+
An early draft spec listed 1=BLOCKED, 2=CONCERNS; that ordering was
|
|
2142
|
+
rejected and is not used anywhere. See docs/exit-codes.md for every
|
|
2143
|
+
command's codes.
|
|
2106
2144
|
|
|
2107
2145
|
OUTPUT:
|
|
2108
2146
|
<out>/evidence.json consolidated machine-readable evidence (schema 1.0)
|
|
@@ -2620,6 +2658,8 @@ verify_main() {
|
|
|
2620
2658
|
# verify does NOT re-run gates: it reads a prior evidence.json and fails
|
|
2621
2659
|
# closed if the repo has drifted since that evidence was graded.
|
|
2622
2660
|
VERIFY_CHECK_FRESH=0
|
|
2661
|
+
# Opt-in machine-readable stdout (--json). Default 0 = exactly today.
|
|
2662
|
+
VERIFY_JSON=0
|
|
2623
2663
|
|
|
2624
2664
|
# Fail-closed defaults. These globals are read at the end of this function
|
|
2625
2665
|
# (the VERDICT banner and the function return code). verify_compute_verdict()
|
|
@@ -2644,6 +2684,16 @@ verify_main() {
|
|
|
2644
2684
|
block_on="$(printf '%s' "${2:-}" | tr '[:upper:]' '[:lower:]')"; shift 2 ;;
|
|
2645
2685
|
--no-llm)
|
|
2646
2686
|
shift ;;
|
|
2687
|
+
--json)
|
|
2688
|
+
# Emit the evidence document to STDOUT so a caller can pipe it.
|
|
2689
|
+
# The same document is still written to <out>/evidence.json --
|
|
2690
|
+
# this adds a pipe, it does not move the artifact.
|
|
2691
|
+
#
|
|
2692
|
+
# Implies --quiet-banner: stdout must be JSON and nothing else,
|
|
2693
|
+
# or `loki verify --json | jq` breaks on the human banner. The
|
|
2694
|
+
# banner still goes to stderr, so an operator watching a
|
|
2695
|
+
# terminal loses nothing.
|
|
2696
|
+
VERIFY_JSON=1; shift ;;
|
|
2647
2697
|
--explain)
|
|
2648
2698
|
# Render a one-screen, skeptic-legible trust proof: every gate
|
|
2649
2699
|
# that ran, its status, the runner/scanner that produced the
|
|
@@ -2793,10 +2843,21 @@ verify_main() {
|
|
|
2793
2843
|
|
|
2794
2844
|
completed_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
2795
2845
|
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2846
|
+
# stdout is discarded (the emitter's own chatter is not wanted on the human
|
|
2847
|
+
# path). Under --json, FD 3 is opened onto the REAL stdout so the emitter
|
|
2848
|
+
# can write the evidence document there while everything else stays
|
|
2849
|
+
# suppressed -- that is what keeps `loki verify --json | jq` parseable.
|
|
2850
|
+
if [ "${VERIFY_JSON:-0}" = "1" ]; then
|
|
2851
|
+
verify_emit_evidence "$out_dir" "$started_at" "$completed_at" "$block_on" 3>&1 >/dev/null || {
|
|
2852
|
+
_verify_err "failed to emit evidence document"
|
|
2853
|
+
return $VERIFY_EXIT_ERROR
|
|
2854
|
+
}
|
|
2855
|
+
else
|
|
2856
|
+
verify_emit_evidence "$out_dir" "$started_at" "$completed_at" "$block_on" >/dev/null || {
|
|
2857
|
+
_verify_err "failed to emit evidence document"
|
|
2858
|
+
return $VERIFY_EXIT_ERROR
|
|
2859
|
+
}
|
|
2860
|
+
fi
|
|
2800
2861
|
|
|
2801
2862
|
# Opt-in (--hosted): fold the embedded Autonomi Verify engine's verdict
|
|
2802
2863
|
# fields into the just-written evidence.json. Fully additive and fail-open:
|
|
@@ -2814,9 +2875,14 @@ verify_main() {
|
|
|
2814
2875
|
_verify_render_explain "$started_at" "$completed_at" "$VERIFY_VERDICT"
|
|
2815
2876
|
fi
|
|
2816
2877
|
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2878
|
+
# Under --json stdout carries the evidence document alone, so the human
|
|
2879
|
+
# banner is redirected to stderr rather than dropped: an operator watching a
|
|
2880
|
+
# terminal still sees the verdict, and `| jq` still parses.
|
|
2881
|
+
_v_banner_fd=1
|
|
2882
|
+
[ "${VERIFY_JSON:-0}" = "1" ] && _v_banner_fd=2
|
|
2883
|
+
printf 'VERDICT: %s\n' "$VERIFY_VERDICT" >&$_v_banner_fd
|
|
2884
|
+
printf 'Evidence: %s/evidence.json\n' "$out_dir" >&$_v_banner_fd
|
|
2885
|
+
printf 'Report: %s/report.md\n' "$out_dir" >&$_v_banner_fd
|
|
2820
2886
|
# --hosted only: surface the enrichment in human output so the extra signal
|
|
2821
2887
|
# is visible without parsing JSON. Printed solely when a fold succeeded;
|
|
2822
2888
|
# the default path never sets VERIFY_HOSTED_SUMMARY, so it stays byte-identical.
|
package/completions/_loki
CHANGED
|
@@ -153,6 +153,7 @@ function _loki_commands {
|
|
|
153
153
|
'memory:Memory commands'
|
|
154
154
|
'compound:Knowledge compounding commands'
|
|
155
155
|
'checkpoint:Snapshot and restore session state'
|
|
156
|
+
'cp:Snapshot and restore session state (alias of checkpoint)'
|
|
156
157
|
'council:Completion council commands'
|
|
157
158
|
'dogfood:Self-development statistics'
|
|
158
159
|
'projects:Project registry commands'
|
package/completions/loki.bash
CHANGED
|
@@ -5,7 +5,7 @@ _loki_completion() {
|
|
|
5
5
|
_init_completion || return
|
|
6
6
|
|
|
7
7
|
# Main subcommands (must match autonomy/loki main case statement)
|
|
8
|
-
local main_commands="start quick monitor demo tour welcome init stop pause resume steer status next ship dashboard web serve api sandbox notify import github issue config provider reset memory compound checkpoint council dogfood projects enterprise secrets cockpit secure own doctor watchdog audit metrics syslog onboard share proof explain plan report cost kpis stats test ci watch telemetry agent context ctx code run export review optimize heal modernize migrate cluster worktree wt trigger failover remote deploy docker mcp magic assets analyze compliance crash open otel preview quickstart rc rollback self-update sentrux setup-skill spec state template trust trust-metrics ultracode update verify voice why wiki bench cleanup logs grill docs cp version completions help"
|
|
8
|
+
local main_commands="start quick monitor demo tour welcome init stop pause resume steer status next ship dashboard web serve api sandbox notify import github issue config provider reset memory compound checkpoint council dogfood projects enterprise secrets cockpit secure own handoff doctor watchdog audit metrics syslog onboard share proof receipt explain plan report cost kpis stats test ci watch telemetry agent context ctx code run export review optimize heal modernize migrate cluster worktree wt trigger failover remote deploy docker mcp magic assets analyze compliance crash open otel preview quickstart rc rollback self-update sentrux setup-skill spec state template trust trust-metrics ultracode update verify voice why wiki bench cleanup logs grill docs cp version completions help"
|
|
9
9
|
|
|
10
10
|
# 1. If we are on the first argument (subcommand)
|
|
11
11
|
if [[ $cword -eq 1 ]]; then
|
package/dashboard/__init__.py
CHANGED
package/docs/EVALUATING.md
CHANGED
|
@@ -154,6 +154,34 @@ expose something the CLI does not. If a competitor does ship output
|
|
|
154
154
|
verification, this test is how we would find out, and the claim above would be
|
|
155
155
|
corrected rather than defended.
|
|
156
156
|
|
|
157
|
+
## 7. Headless latency, five trials per tool
|
|
158
|
+
|
|
159
|
+
Same task, same machine, artifact verified by content, five trials each:
|
|
160
|
+
|
|
161
|
+
| CLI | Success | Median | Range |
|
|
162
|
+
| --- | --- | --- | --- |
|
|
163
|
+
| opencode 1.18.9 | 5/5 | 11s | 4s to 265s |
|
|
164
|
+
| codex-cli 0.146.0 | 4/5 | 69s | 48s to 80s (one 300s timeout) |
|
|
165
|
+
|
|
166
|
+
**Read the range, not just the median.** opencode's first trial took 265
|
|
167
|
+
seconds and the next four took 4 to 12. A new user experiences the 265, not the
|
|
168
|
+
11. Reporting only the median would hide the thing they will actually feel.
|
|
169
|
+
|
|
170
|
+
**The timeout is kept in.** Dropping codex's one failure would turn 4-of-5 into
|
|
171
|
+
an implied 5-of-5 and overstate reliability.
|
|
172
|
+
|
|
173
|
+
**Five trials, not one, and that is the point.** An earlier single-shot run of
|
|
174
|
+
this same codex command timed out, and publishing it would have recorded
|
|
175
|
+
"codex: timeout" as a fact about a competitor when the identical command
|
|
176
|
+
completed in 51 seconds minutes later. The spread is the finding.
|
|
177
|
+
|
|
178
|
+
**What this does not measure.** One trivial file-creation task is not a proxy
|
|
179
|
+
for build quality, multi-iteration work, or brownfield capability. It measures
|
|
180
|
+
headless invocation latency and nothing else. aider, Claude Code and
|
|
181
|
+
cursor-agent have not been run on this task; Devin and Replit Agent ship no
|
|
182
|
+
local CLI. Cost is not compared: codex ran on a free tier and opencode's
|
|
183
|
+
per-call cost was not recorded.
|
|
184
|
+
|
|
157
185
|
---
|
|
158
186
|
|
|
159
187
|
## What we do not have
|
package/docs/PRIVACY.md
CHANGED
|
@@ -114,10 +114,33 @@ it sits below the base telemetry gate, every telemetry opt-out (`loki telemetry
|
|
|
114
114
|
off` / `LOKI_TELEMETRY=off` / `DO_NOT_TRACK=1`) also disables it -- opt-out
|
|
115
115
|
always wins.
|
|
116
116
|
|
|
117
|
+
### 5. First-run blocker (anonymous, STRICT opt-in, default OFF)
|
|
118
|
+
|
|
119
|
+
A `first_run_blocked` event naming which CLASS of dependency stopped a first
|
|
120
|
+
run, sent at most ONCE per install. It sits behind the same strict second
|
|
121
|
+
opt-in as build-outcome analytics above (`LOKI_ANALYTICS=on`), so it is off by
|
|
122
|
+
default even with telemetry enabled.
|
|
123
|
+
|
|
124
|
+
It exists because we could see that a first run was ATTEMPTED and nothing about
|
|
125
|
+
whether it succeeded, which made "why does a trial not convert" unanswerable.
|
|
126
|
+
A real example we found and fixed: on a machine with no AI provider CLI, one
|
|
127
|
+
route ended with a dead end instead of pointing at `loki tour` (which needs no
|
|
128
|
+
provider, no key and no spend). Nobody could see that happening.
|
|
129
|
+
|
|
130
|
+
The ONLY field is `blocker`, clamped to this fixed enum:
|
|
131
|
+
|
|
132
|
+
no_provider | node | python3 | jq | git | curl | disk | skill_symlink | other
|
|
133
|
+
|
|
134
|
+
Anything not on that list becomes `other`. It is deliberately coarse: `node` is
|
|
135
|
+
enough to act on, and a version string or an install path would be a leak. It
|
|
136
|
+
NEVER sends paths, versions, hostnames, spec text, or command lines -- a test
|
|
137
|
+
(`tests/test-first-run-blocked-signal.sh`) feeds a filesystem path through the
|
|
138
|
+
real emitter and fails the build if anything but `other` reaches the payload.
|
|
139
|
+
|
|
117
140
|
This document and the first-run notice describe ALL paths. The model is unified:
|
|
118
141
|
opt-out always wins and disables everything; crash reporting and usage telemetry
|
|
119
|
-
opt in together (default ON for individuals); build-outcome analytics
|
|
120
|
-
|
|
142
|
+
opt in together (default ON for individuals); build-outcome analytics and the
|
|
143
|
+
first-run blocker each need an explicit second opt-in on top (default OFF).
|
|
121
144
|
|
|
122
145
|
## What is collected (the whitelist)
|
|
123
146
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Running without egress
|
|
2
|
+
|
|
3
|
+
If your code cannot leave your network, most of this category is unavailable to
|
|
4
|
+
you regardless of what the sales conversation suggests.
|
|
5
|
+
|
|
6
|
+
## Where the tools actually stand
|
|
7
|
+
|
|
8
|
+
Verified from vendor documentation, 2026-07-31:
|
|
9
|
+
|
|
10
|
+
| Tool | Air-gapped |
|
|
11
|
+
|---|---|
|
|
12
|
+
| Devin | **No.** Single-tenant VPC via AWS PrivateLink, customer-managed KMS, a federal docs tree -- but "Devin's brain... always resides within Cognition's Cloud." |
|
|
13
|
+
| Cursor | No. Cloud service; embeddings are uploaded (obfuscated and encrypted). |
|
|
14
|
+
| Claude Code | Partly. Runs against Bedrock / Vertex / Foundry in your own cloud, so data residency is yours -- but a model endpoint is still required. |
|
|
15
|
+
| Lovable, Replit, Emergent | No. Browser products on their infrastructure. |
|
|
16
|
+
| opencode | Structurally yes (MIT, self-hostable) -- but no SOC2, SSO, audit logs, or support. |
|
|
17
|
+
|
|
18
|
+
Devin's is the strongest enterprise packaging in the category and it still
|
|
19
|
+
cannot run disconnected. That is a structural property of a hosted control
|
|
20
|
+
plane, not an oversight.
|
|
21
|
+
|
|
22
|
+
## What we measured
|
|
23
|
+
|
|
24
|
+
Executed 2026-07-31 with outbound HTTP forced through an unroutable proxy --
|
|
25
|
+
not a flag, not an assumption. Every one of these returned a real result with
|
|
26
|
+
egress severed:
|
|
27
|
+
|
|
28
|
+
| Command | Result |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `loki version` | works |
|
|
31
|
+
| `loki doctor --json` | works |
|
|
32
|
+
| `loki plan <spec> --json` | works -- full cost and complexity estimate |
|
|
33
|
+
| `loki proof list` | works |
|
|
34
|
+
| `loki proof verify <id>` | works, and correctly reported `tree_drift: true` |
|
|
35
|
+
| `loki heal <repo> --assess --json` | works -- maturity, ranked targets, runtime |
|
|
36
|
+
|
|
37
|
+
The whole evaluate-before-you-buy path runs disconnected. You can assess a
|
|
38
|
+
legacy codebase, estimate what a build would cost, and verify an existing
|
|
39
|
+
receipt without a single packet leaving the machine.
|
|
40
|
+
|
|
41
|
+
`loki proof verify` deserves emphasis: an auditor can re-check a receipt against
|
|
42
|
+
the repository offline and get a genuine verdict, including detecting drift.
|
|
43
|
+
That is the property competitors' dashboard-bound verification cannot have.
|
|
44
|
+
|
|
45
|
+
## The one required egress, stated plainly
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
loki doctor --airgap
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
prints the egress inventory. Today it reports exactly one REQUIRED point:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
REQUIRED model inference -> https://api.anthropic.com
|
|
55
|
+
Set ANTHROPIC_BASE_URL to an in-network gateway, or switch to a
|
|
56
|
+
local-weights provider.
|
|
57
|
+
optional telemetry [off] disable: loki telemetry off (default off)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**We cannot run a build with no model at all.** Nobody can. What we can do is
|
|
61
|
+
let you point at a model you host: set `ANTHROPIC_BASE_URL` to an in-network
|
|
62
|
+
gateway, or run a provider with local weights. The engine abstracts over CLIs
|
|
63
|
+
rather than over one vendor's API.
|
|
64
|
+
|
|
65
|
+
Telemetry is off by default and every opt-out wins (`DO_NOT_TRACK=1`,
|
|
66
|
+
`LOKI_TELEMETRY=off`, `~/.loki/config`). The adoption instrumentation added in
|
|
67
|
+
v8.6.0 requires a second explicit opt-in on top of that -- see
|
|
68
|
+
[PRIVACY.md](./PRIVACY.md).
|
|
69
|
+
|
|
70
|
+
## Why `unknown` is the right answer offline
|
|
71
|
+
|
|
72
|
+
`loki heal --assess` reports `dependency_staleness: unknown` and always will
|
|
73
|
+
without a network call. We know your manifest pins lodash 3.x; we do not know
|
|
74
|
+
what is current upstream, and we will not guess.
|
|
75
|
+
|
|
76
|
+
That refusal is what makes the assessment trustworthy inside a disconnected
|
|
77
|
+
network. A tool that fabricates a staleness number offline is more dangerous
|
|
78
|
+
than one that declines.
|
|
79
|
+
|
|
80
|
+
## Honest limits
|
|
81
|
+
|
|
82
|
+
- **A model endpoint is required.** If you have no model at all -- not local,
|
|
83
|
+
not in-network -- we cannot build anything, and neither can anyone else.
|
|
84
|
+
- **The five mutating healing phases need a provider.** Only `--assess` is
|
|
85
|
+
genuinely zero-dependency.
|
|
86
|
+
- **Not measured here:** a full disconnected build against a local-weights
|
|
87
|
+
provider. The commands above were measured; that one was not, and this page
|
|
88
|
+
does not claim it.
|
|
89
|
+
|
|
90
|
+
See [Kubernetes air-gapped install](../deploy/helm/README.md) for the
|
|
91
|
+
cluster-side path.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Working on a codebase you already have
|
|
2
|
+
|
|
3
|
+
Most of this category is built for starting from nothing. If you already have a
|
|
4
|
+
repository -- especially a large, private, awkward one -- your options narrow
|
|
5
|
+
fast.
|
|
6
|
+
|
|
7
|
+
## Where the tools actually stand
|
|
8
|
+
|
|
9
|
+
Verified from vendor documentation, 2026-07-31:
|
|
10
|
+
|
|
11
|
+
| Tool | Existing repository |
|
|
12
|
+
|---|---|
|
|
13
|
+
| Lovable | **Cannot import one.** "You can only export from Lovable to GitHub"; two-way sync begins only after Lovable creates the repo. |
|
|
14
|
+
| Replit Agent | Imports GitHub (public and private), Figma, ZIP -- into Replit's environment. |
|
|
15
|
+
| Cursor | Indexes your repo; embeddings are uploaded, obfuscated and encrypted. |
|
|
16
|
+
| Devin | Indexes the repo, plus YAML blueprints producing snapshots each session boots from. |
|
|
17
|
+
| Loki | Runs in place, where the code already is. |
|
|
18
|
+
|
|
19
|
+
That last row is the whole difference, and it is not a preference. For a private
|
|
20
|
+
monorepo with internal dependencies and submodules, "upload it to our
|
|
21
|
+
environment" is often not a thing anyone is permitted to do.
|
|
22
|
+
|
|
23
|
+
**Credit where it is due:** Devin has the strongest documented modernization
|
|
24
|
+
story of the four -- named playbooks for COBOL, Java upgrades, and
|
|
25
|
+
SAS-to-PySpark. If you want a vendor-run modernization program, look at them
|
|
26
|
+
seriously. What follows is what we do differently, not a claim that they are
|
|
27
|
+
bad at this.
|
|
28
|
+
|
|
29
|
+
## Start here: a read-only assessment that costs nothing
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
loki heal ./your-repo --assess --json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
No provider call, no API key, no spend, no writes. It reports:
|
|
36
|
+
|
|
37
|
+
- a **maturity level** with the reason stated (for example: "No test/spec files
|
|
38
|
+
detected: changes are unguarded")
|
|
39
|
+
- **ranked targets** with blast-radius reasoning per file ("isolated (no inbound
|
|
40
|
+
imports -> low blast radius), 12 LOC")
|
|
41
|
+
- **debt signals**: test ratio, TODO density
|
|
42
|
+
- **the runtime it declares**: Node engine constraint, dependency count, and the
|
|
43
|
+
frameworks actually present in the manifest
|
|
44
|
+
- **dependency lock status**
|
|
45
|
+
|
|
46
|
+
This is the honest opening move: you learn where to start before committing to
|
|
47
|
+
anything.
|
|
48
|
+
|
|
49
|
+
### What it deliberately does not tell you
|
|
50
|
+
|
|
51
|
+
`dependency_staleness` reports `unknown`, always, offline. We know your manifest
|
|
52
|
+
pins lodash 3.x; we do not know what is current upstream without a network call,
|
|
53
|
+
and we will not guess. That refusal is the same reason the assessment works
|
|
54
|
+
inside an air-gapped network at all.
|
|
55
|
+
|
|
56
|
+
## The healing phases
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
loki heal ./your-repo --phase archaeology # map dependencies, catalog friction
|
|
60
|
+
loki heal ./your-repo --phase stabilize # add observability and tests, no behavior change
|
|
61
|
+
loki heal ./your-repo --phase isolate # adapter boundaries between components
|
|
62
|
+
loki heal ./your-repo --phase modernize # replace one component at a time, behind adapters
|
|
63
|
+
loki heal ./your-repo --phase validate # prove behavioral equivalence against the baseline
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
These call a provider and cost money. `--assess` does not.
|
|
67
|
+
|
|
68
|
+
## Behavioral equivalence is the part worth arguing about
|
|
69
|
+
|
|
70
|
+
Every tool in this category will tell you it preserved your business logic.
|
|
71
|
+
Devin's COBOL page says it preserves "critical functionality." What none of them
|
|
72
|
+
document is a *procedure* for proving it.
|
|
73
|
+
|
|
74
|
+
That is the axis we build on:
|
|
75
|
+
|
|
76
|
+
- **characterization tests** capture what the system does today, quirks
|
|
77
|
+
included, before anything is modernized
|
|
78
|
+
- **friction classification** distinguishes accidental mess from load-bearing
|
|
79
|
+
weirdness -- the 30-second sleep that looks stupid and is actually a race-
|
|
80
|
+
condition fix nobody documented
|
|
81
|
+
- **a backward-compatibility auditor** blocks removal of unclassified friction
|
|
82
|
+
- **the validate phase** checks behavior against the recorded baseline
|
|
83
|
+
|
|
84
|
+
Then the [Evidence Receipt](../README.md#the-evidence-receipt-dont-trust-the-agent-check-it)
|
|
85
|
+
records what was proven and what was not, bound to the specific diff.
|
|
86
|
+
|
|
87
|
+
"We prove behavior is unchanged" is a stronger claim than "we preserve business
|
|
88
|
+
logic," and it is the one you can check.
|
|
89
|
+
|
|
90
|
+
The full procedure -- what each phase does, what the friction taxonomy
|
|
91
|
+
distinguishes, and where the safety gates sit -- is in
|
|
92
|
+
[skills/healing.md](../skills/healing.md), with the research it draws on in
|
|
93
|
+
[references/legacy-healing-patterns.md](../references/legacy-healing-patterns.md).
|
|
94
|
+
|
|
95
|
+
### The friction question, concretely
|
|
96
|
+
|
|
97
|
+
The hardest part of a legacy migration is not translating syntax. It is telling
|
|
98
|
+
the difference between:
|
|
99
|
+
|
|
100
|
+
- a `sleep 30` that is genuinely dead weight, and
|
|
101
|
+
- a `sleep 30` that is the only thing preventing a race condition nobody wrote
|
|
102
|
+
down, whose author left in 2019
|
|
103
|
+
|
|
104
|
+
Delete the second and the system breaks in production, weeks later, in a way
|
|
105
|
+
nobody connects to the migration. This is why the auditor blocks removal of
|
|
106
|
+
*unclassified* friction: not because the friction is sacred, but because
|
|
107
|
+
"we do not know what this does yet" is a real state that deserves a name
|
|
108
|
+
instead of a guess.
|
|
109
|
+
|
|
110
|
+
## Honest scope
|
|
111
|
+
|
|
112
|
+
- **Measured and working:** `--assess` on real repositories, verified by
|
|
113
|
+
execution.
|
|
114
|
+
- **Implemented, not measured here:** the five mutating phases need a provider
|
|
115
|
+
and real spend; this page does not claim an end-to-end benchmark we have not
|
|
116
|
+
published.
|
|
117
|
+
- **We do not do COBOL.** If your problem is a mainframe, we are not your
|
|
118
|
+
answer today.
|
|
119
|
+
- **Your code stays put.** Nothing is uploaded to us -- there is no "us" in the
|
|
120
|
+
data path. See [cost controls](./cost-controls.md) for how spend is bounded.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Cost controls
|
|
2
|
+
|
|
3
|
+
You set the ceiling. We stop at it, and the receipt tells you where the money
|
|
4
|
+
went.
|
|
5
|
+
|
|
6
|
+
## Why this page exists
|
|
7
|
+
|
|
8
|
+
"I paid for the AI's own mistakes" is one of the sharpest complaints in this
|
|
9
|
+
category, and it is worth being precise about how our model differs.
|
|
10
|
+
|
|
11
|
+
Most competitors sell credits. Lovable has already addressed the objection
|
|
12
|
+
directly -- their "Try to fix" button does not consume credits, and their
|
|
13
|
+
troubleshooting docs push you toward reverting or replanning instead of
|
|
14
|
+
retrying the same prompt. That is a good policy and we are not claiming to have
|
|
15
|
+
invented a better one.
|
|
16
|
+
|
|
17
|
+
**Our model is different in kind: you bring your own provider credentials.** We
|
|
18
|
+
never bill you, because we are never in the payment path. What we owe you
|
|
19
|
+
instead is a hard ceiling and an honest account of what was spent -- which is
|
|
20
|
+
what this page describes.
|
|
21
|
+
|
|
22
|
+
## The three caps
|
|
23
|
+
|
|
24
|
+
They bound different things, and a run that stalls needs all three.
|
|
25
|
+
|
|
26
|
+
| Cap | Bounds | Default |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `LOKI_BUDGET_LIMIT` | Total spend, in USD | unset (no cap) |
|
|
29
|
+
| `LOKI_MAX_ITERATIONS` | Number of iterations | 1000 |
|
|
30
|
+
| `LOKI_MAX_DURATION` | Wall-clock time | unset (no cap) |
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
LOKI_BUDGET_LIMIT=25 loki start ./prd.md
|
|
34
|
+
loki start ./prd.md --max-duration 90m
|
|
35
|
+
loki config set budget 25
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Why three and not one.** Spend and iterations both assume forward progress. A
|
|
39
|
+
run that *stalls* -- a hung provider call, a wedged subprocess -- burns hours
|
|
40
|
+
while spending almost nothing and completing no iteration, so neither of those
|
|
41
|
+
breakers ever trips. The wall-clock cap is the one that catches it. We added it
|
|
42
|
+
after a run burned $34 reaching an external timeout.
|
|
43
|
+
|
|
44
|
+
## Hitting a cap is a FAILURE, not a success
|
|
45
|
+
|
|
46
|
+
This is the part that matters for anyone automating against us.
|
|
47
|
+
|
|
48
|
+
All three caps produce a **terminal failure**: exit 20 under
|
|
49
|
+
`LOKI_DURABLE_STATE=1`, with a distinct status (`budget_exceeded`,
|
|
50
|
+
`max_iterations_reached`, `max_duration_reached`) so the receipt and `loki why`
|
|
51
|
+
can tell you *which* ceiling you hit and therefore which one to raise.
|
|
52
|
+
|
|
53
|
+
`budget_exceeded` used to exit **0**, on the reasoning that a human would raise
|
|
54
|
+
the cap and resume. That is true at a terminal and false inside a Kubernetes
|
|
55
|
+
Job, where there is no human: the Job went Complete, the pipeline went green,
|
|
56
|
+
and an incomplete build looked finished. Exit 0 now means the work is finished
|
|
57
|
+
or a person deliberately stopped it -- never that we ran out of money mid-task.
|
|
58
|
+
|
|
59
|
+
See [exit codes](./exit-codes.md) for the full contract.
|
|
60
|
+
|
|
61
|
+
## Preview the cost before spending anything
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
loki plan ./prd.md --json
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Reports complexity, estimated iterations, token usage and cost **without
|
|
68
|
+
executing**. No provider call, no spend. `LOKI_CONFIG_DUMP=1 loki start ./prd.md`
|
|
69
|
+
prints the resolved configuration and exits, so you can confirm your caps are
|
|
70
|
+
actually set before a real run.
|
|
71
|
+
|
|
72
|
+
## What you are charged for, stated plainly
|
|
73
|
+
|
|
74
|
+
Every iteration calls your provider, including iterations spent re-running
|
|
75
|
+
after a quality gate fails. **We do not exempt our own gate failures from your
|
|
76
|
+
budget**, and pretending otherwise would be dishonest -- those calls really do
|
|
77
|
+
consume your tokens.
|
|
78
|
+
|
|
79
|
+
What we do instead:
|
|
80
|
+
|
|
81
|
+
- the caps above bound the total, so a doom loop has a hard ceiling
|
|
82
|
+
- the Evidence Receipt records iteration count and cost, so a re-run is visible
|
|
83
|
+
rather than buried
|
|
84
|
+
- reaching a cap reports as a failure with the reason named, so you know whether
|
|
85
|
+
to raise the ceiling or narrow the spec
|
|
86
|
+
|
|
87
|
+
If a run cost more than you expected, `loki proof show <id>` tells you where it
|
|
88
|
+
went.
|