loki-mode 8.1.0 → 8.3.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 +87 -1
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/completion-council.sh +45 -4
- package/autonomy/council-v2.sh +63 -1
- package/autonomy/grill.sh +32 -0
- package/autonomy/lib/done-recognition.sh +16 -4
- package/autonomy/lib/fast_verify.py +346 -0
- package/autonomy/lib/no_mock_scan.py +21 -1
- package/autonomy/lib/prd-enrich.sh +7 -1
- package/autonomy/lib/proof-generator.py +146 -6
- package/autonomy/lib/proof-template.html +60 -12
- package/autonomy/lib/proof-verify.py +52 -0
- package/autonomy/loki +236 -12
- package/autonomy/verify.sh +12 -6
- package/dashboard/__init__.py +1 -1
- package/docs/COMPARISON.md +8 -1
- package/docs/EVALUATING.md +142 -0
- package/events/emit.sh +66 -6
- package/loki-ts/dist/loki.js +319 -316
- package/mcp/__init__.py +30 -12
- package/mcp/server.py +150 -0
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/providers/claude.sh +72 -0
- package/providers/codex.sh +13 -0
- package/providers/loader.sh +10 -4
- package/providers/model_catalog.json +50 -0
- package/providers/models.sh +26 -3
- package/providers/opencode.sh +145 -0
- package/references/design-archetypes.md +85 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Evaluating Loki Mode
|
|
2
|
+
|
|
3
|
+
For someone deciding whether to trust an autonomous coding agent with a real
|
|
4
|
+
codebase. Every claim below has a command next to it. Run them; do not take our
|
|
5
|
+
word for it.
|
|
6
|
+
|
|
7
|
+
We have deliberately not written a feature grid scoring ourselves against ten
|
|
8
|
+
competitors. Those grids are written by the vendor being scored, the criteria
|
|
9
|
+
are chosen by the vendor, and no reader can check a single cell. This page only
|
|
10
|
+
makes claims you can falsify in a terminal.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. The agent hands you a receipt, and it admits what it did not verify
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx loki-mode tour # no install, no API key, no spend, no network
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Output includes:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Headline: VERIFIED WITH GAPS
|
|
24
|
+
|
|
25
|
+
| Files changed | 8 |
|
|
26
|
+
| Diff sha256 | c2be6fff3e774c387f276277b25fc424f07b667… |
|
|
27
|
+
| Tests | verified (node-test) |
|
|
28
|
+
| Build | not_run |
|
|
29
|
+
| Security | findings |
|
|
30
|
+
| Cost | $10.3218 |
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**What to notice:** the headline is not "SUCCESS". Build was not run. Security
|
|
34
|
+
has findings. The receipt says so on its own front page.
|
|
35
|
+
|
|
36
|
+
**Why that is the product.** Every coding agent reports its own completion, and
|
|
37
|
+
self-reporting is the thing they are structurally worst at. The receipt
|
|
38
|
+
separates deterministic FACTS (diff hash, test result, cost) from AI
|
|
39
|
+
ASSESSMENTS, because only four of our eight quality gates are agent-independent
|
|
40
|
+
and a receipt implying otherwise would be marketing.
|
|
41
|
+
|
|
42
|
+
**Check it yourself:** recompute the diff sha256 over the same range and confirm
|
|
43
|
+
it matches. If it does not, the receipt is worthless and you should not use us.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 2. Verification runs air-gapped
|
|
48
|
+
|
|
49
|
+
Deterministic verification makes zero network calls, so it runs inside a
|
|
50
|
+
perimeter on code that may never leave the building.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
bash tests/test-airgap-verify.sh
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
That test blackholes every proxy variable, strips the environment, and asserts a
|
|
57
|
+
real verdict still comes back. Measured: **8.43 ms**.
|
|
58
|
+
|
|
59
|
+
**Scope, stated honestly:** verification is air-gapped. **Generation is not.**
|
|
60
|
+
Every provider we ship calls a hosted API, and local-weight generation needs
|
|
61
|
+
models you would supply. We are not claiming the generation half, and any vendor
|
|
62
|
+
who claims a fully air-gapped LLM agent without shipping weights is worth a
|
|
63
|
+
second question.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 3. On an existing codebase, the read-only path is genuinely read-only
|
|
68
|
+
|
|
69
|
+
Brownfield is the harder problem, and the reason to distrust an agent near it is
|
|
70
|
+
obvious. So the entry point writes nothing:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
loki modernize heal ./your-repo --assess
|
|
74
|
+
git status # clean. no scratch files, no .loki/, no commits.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Enforced, not promised:**
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
bash tests/test-brownfield-assess-readonly.sh
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
That test hashes every file before and after, compares HEAD, and requires a
|
|
84
|
+
clean working tree. It is content-addressed, so it does not care *how* a write
|
|
85
|
+
might happen.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 4. The harness is model-invariant (and we do not overclaim it)
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
cat benchmarks/results/cross-model-eval.json
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- **Claimed:** the same gates run, the same acceptance is checked, and the same
|
|
96
|
+
receipt semantics apply regardless of which model is behind it.
|
|
97
|
+
- **Explicitly NOT claimed:** identical quality or identical speed across
|
|
98
|
+
models. That is not deliverable and we do not assert it.
|
|
99
|
+
|
|
100
|
+
Measured runs are in that file with wall-clock and iteration counts. Two runs is
|
|
101
|
+
two runs; it is not a benchmark suite, and the file says so.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 5. Verification is fast enough to embed
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
python3 autonomy/lib/fast_verify.py --path . --diff-base HEAD~1
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Measured on this repository, 1,932 tracked source files: **11,040 ms before,
|
|
112
|
+
19 ms diff-scoped** (298 ms cold, 87 ms warm). That is the difference between a
|
|
113
|
+
check you run at the end and a check something else can call as a dependency.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## What we do not have
|
|
118
|
+
|
|
119
|
+
Stating this plainly, because you will find it out anyway and it is cheaper for
|
|
120
|
+
both of us if you find it here.
|
|
121
|
+
|
|
122
|
+
- **No published enterprise case studies.** We have adoption signal (fork ratio
|
|
123
|
+
well above the norm for a tool this size) but no named enterprise references.
|
|
124
|
+
- **No independent third-party benchmark placement.** The SWE-bench Verified
|
|
125
|
+
leaderboard is months stale and every entry on it is self-reported, ours would
|
|
126
|
+
be too.
|
|
127
|
+
- **No audit of the closed-source products.** We have verified that seven open
|
|
128
|
+
harnesses (OpenHands, Cline, Aider, SWE-agent, Roo-Code, OpenCode, Continue)
|
|
129
|
+
publish no machine-checkable completion artifact. Cursor, Devin, Replit Agent
|
|
130
|
+
and Claude Code we have **not** audited feature by feature, so treat the
|
|
131
|
+
receipt as "unclaimed as far as we can verify", not as a proven first.
|
|
132
|
+
- **Generation is not air-gapped.** See section 2.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## The one question worth asking any agent vendor
|
|
137
|
+
|
|
138
|
+
> When your agent says it finished, what artifact can I check that does not come
|
|
139
|
+
> from the agent's own narrative?
|
|
140
|
+
|
|
141
|
+
Ours is the Evidence Receipt, and section 1 is a two-minute test of whether the
|
|
142
|
+
answer holds up. Ask the same question everywhere else.
|
package/events/emit.sh
CHANGED
|
@@ -71,6 +71,26 @@ safe_append_event_jsonl() {
|
|
|
71
71
|
local max_attempts=100 # ~1s at 10ms sleep
|
|
72
72
|
local stale_after=30
|
|
73
73
|
while ! mkdir "$lock_dir" 2>/dev/null; do
|
|
74
|
+
# COUNT EVERY ITERATION, before any `continue` can skip the increment.
|
|
75
|
+
#
|
|
76
|
+
# This was the v8.1.0 fix's blind spot and it kept the P0 alive. Both
|
|
77
|
+
# `continue` paths below (lock vanished mid-stat; stale lock reclaimed)
|
|
78
|
+
# jumped PAST the increment that used to live at the bottom of the loop,
|
|
79
|
+
# so `max_attempts` was unreachable on those paths and the loop spun
|
|
80
|
+
# forever. Under concurrent emits the stale-reclaim path fires over and
|
|
81
|
+
# over, which is precisely the pathological case.
|
|
82
|
+
#
|
|
83
|
+
# MEASURED 2026-07-30, AFTER the v8.1.0 fix shipped: 63 orphaned
|
|
84
|
+
# emit.sh processes, oldest alive 10h51m, each burning ~5% CPU, machine
|
|
85
|
+
# at load 63 on 14 cores. Every orphan started after the fix landed.
|
|
86
|
+
# An unbounded wait whose only exit is a counter must increment that
|
|
87
|
+
# counter on EVERY path, or the bound is decorative.
|
|
88
|
+
attempts=$((attempts + 1))
|
|
89
|
+
if [ "$attempts" -ge "$max_attempts" ]; then
|
|
90
|
+
# Give up fast -- best-effort write so observability never blocks.
|
|
91
|
+
printf '%s\n' "$line" >> "$events_path" 2>/dev/null || true
|
|
92
|
+
return 0
|
|
93
|
+
fi
|
|
74
94
|
# Check staleness EVERY iteration, not only after exhausting attempts.
|
|
75
95
|
# The old code waited for all 500 attempts before its first staleness
|
|
76
96
|
# check, so a stale lock cost ~5s AND ~500 forked sleep helpers per
|
|
@@ -90,12 +110,8 @@ safe_append_event_jsonl() {
|
|
|
90
110
|
rmdir "$lock_dir" 2>/dev/null || rm -rf "$lock_dir" 2>/dev/null || true
|
|
91
111
|
continue
|
|
92
112
|
fi
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
# Give up fast -- best-effort write so observability never blocks.
|
|
96
|
-
printf '%s\n' "$line" >> "$events_path" 2>/dev/null || true
|
|
97
|
-
return 0
|
|
98
|
-
fi
|
|
113
|
+
# (attempt counting and the give-up branch moved to the TOP of the loop
|
|
114
|
+
# so no `continue` can bypass them)
|
|
99
115
|
# Sleep ~10ms WITHOUT forking when the shell supports fractional sleep
|
|
100
116
|
# (bash's `read -t` needs no external process). perl/sleep are fallbacks.
|
|
101
117
|
read -r -t 0.01 _unused_ < /dev/null 2>/dev/null \
|
|
@@ -117,6 +133,50 @@ fi
|
|
|
117
133
|
|
|
118
134
|
set -euo pipefail
|
|
119
135
|
|
|
136
|
+
#-----------------------------------------------------------------------------
|
|
137
|
+
# SELF-REAPER: telemetry must never outlive the thing it observes.
|
|
138
|
+
#-----------------------------------------------------------------------------
|
|
139
|
+
# WHY A WATCHDOG AND NOT ANOTHER LOCK FIX. v8.1.0 fixed a specific unbounded
|
|
140
|
+
# wait (bare `flock -x`, and a staleness check that ran only after 500 attempts).
|
|
141
|
+
# It was a real fix and it was not sufficient: MEASURED 2026-07-30, AFTER that
|
|
142
|
+
# release, 63 orphaned emit.sh processes were alive on this machine, the oldest
|
|
143
|
+
# 10h51m, each burning ~5% CPU, contributing to load 63 on 14 cores. Every one
|
|
144
|
+
# of them started AFTER the fix landed, so whatever wedges emit.sh is not (only)
|
|
145
|
+
# the path that was fixed.
|
|
146
|
+
#
|
|
147
|
+
# The lesson is that patching each discovered hang is an arms race we keep
|
|
148
|
+
# losing, because a hang anywhere in this script has the same user-visible cost.
|
|
149
|
+
# emit.sh is FIRE-AND-FORGET telemetry: nothing waits on its result, and a
|
|
150
|
+
# dropped event is strictly cheaper than a wedged process. So instead of proving
|
|
151
|
+
# no path can block, we cap the lifetime of EVERY path.
|
|
152
|
+
#
|
|
153
|
+
# A background timer SIGKILLs this process after LOKI_EMIT_MAX_SECONDS (default
|
|
154
|
+
# 10). It is deliberately blunt: no cleanup hook, no graceful drain, because the
|
|
155
|
+
# failure mode being defended against is precisely "graceful paths did not run".
|
|
156
|
+
# The killer is disowned so it never becomes a job the parent shell waits on,
|
|
157
|
+
# and it exits immediately when the main process finishes normally.
|
|
158
|
+
#
|
|
159
|
+
# Set LOKI_EMIT_MAX_SECONDS=0 to disable (useful only when debugging emit.sh
|
|
160
|
+
# itself -- an operator who disables it is choosing the orphan risk knowingly).
|
|
161
|
+
_emit_max="${LOKI_EMIT_MAX_SECONDS:-10}"
|
|
162
|
+
case "$_emit_max" in ''|*[!0-9]*) _emit_max=10 ;; esac
|
|
163
|
+
if [ "$_emit_max" -gt 0 ]; then
|
|
164
|
+
_emit_target=$$
|
|
165
|
+
(
|
|
166
|
+
# Poll rather than one long sleep so the watchdog exits promptly on the
|
|
167
|
+
# normal path instead of lingering for the full window.
|
|
168
|
+
_waited=0
|
|
169
|
+
while [ "$_waited" -lt "$_emit_max" ]; do
|
|
170
|
+
sleep 1
|
|
171
|
+
kill -0 "$_emit_target" 2>/dev/null || exit 0
|
|
172
|
+
_waited=$((_waited + 1))
|
|
173
|
+
done
|
|
174
|
+
kill -9 "$_emit_target" 2>/dev/null || true
|
|
175
|
+
) >/dev/null 2>&1 &
|
|
176
|
+
# Disown so the watchdog is not a tracked job of the caller's shell.
|
|
177
|
+
disown 2>/dev/null || true
|
|
178
|
+
fi
|
|
179
|
+
|
|
120
180
|
# Configuration
|
|
121
181
|
LOKI_DIR="${LOKI_DIR:-.loki}"
|
|
122
182
|
EVENTS_DIR="$LOKI_DIR/events/pending"
|