loki-mode 8.32.0 → 8.34.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/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/run.sh +67 -1
- package/dashboard/__init__.py +1 -1
- package/docs/MODEL-REGISTRY-PLAN.md +155 -0
- package/docs/SPEED-AND-FIRST-PASS-PLAN.md +239 -0
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Autonomous spec-driven build system with a built-in trust layer. It does not call work done until it is verified (RARV-C closure loop, 8 quality gates, completion council, verified-completion evidence gate). Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v8.
|
|
6
|
+
# Loki Mode v8.34.0
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -469,4 +469,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
469
469
|
|
|
470
470
|
---
|
|
471
471
|
|
|
472
|
-
**v8.
|
|
472
|
+
**v8.34.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
8.
|
|
1
|
+
8.34.0
|
package/autonomy/run.sh
CHANGED
|
@@ -14330,6 +14330,43 @@ reviewers = mandatory + [
|
|
|
14330
14330
|
}
|
|
14331
14331
|
for name in installed_selected
|
|
14332
14332
|
]
|
|
14333
|
+
# TOTAL council cap (LOKI_REVIEW_MAX_REVIEWERS). The tier map sizes the
|
|
14334
|
+
# SPECIALIST slots ({simple:2, standard:2, complex:4}), but installed agents and
|
|
14335
|
+
# the dependency-analyst append AFTER that sizing, so nothing bounded the total.
|
|
14336
|
+
# Measured consequence, from real code_review_start/complete pairs:
|
|
14337
|
+
#
|
|
14338
|
+
# 3 reviewers -> 31s 6 reviewers -> 177s
|
|
14339
|
+
# 7 reviewers -> 280s 7 reviewers -> 502s
|
|
14340
|
+
#
|
|
14341
|
+
# Dispatch is already concurrent, so this superlinearity is the max-of-N tail
|
|
14342
|
+
# plus contention on one provider -- a scoped issue was drawing a 7-member
|
|
14343
|
+
# council (including two overlapping security reviewers) and paying 9-16x the
|
|
14344
|
+
# 3-member wall clock for it.
|
|
14345
|
+
#
|
|
14346
|
+
# TRIMMING ORDER IS A SAFETY PROPERTY. Mandatory reviewers
|
|
14347
|
+
# (requirements-verifier, architecture-strategist, maintainer-mergeability) are
|
|
14348
|
+
# NEVER dropped: each carries a mandate no keyword-selected specialist has, and
|
|
14349
|
+
# shrinking a council must never be able to manufacture an approval. Only the
|
|
14350
|
+
# appended tail (installed agents, then keyword specialists beyond the floor) is
|
|
14351
|
+
# trimmed, and the cap can never cut below the mandatory set.
|
|
14352
|
+
#
|
|
14353
|
+
# Default 0 = uncapped, preserving today's behaviour exactly. This is a knob to
|
|
14354
|
+
# be turned on deliberately per route, not a silent change to every council.
|
|
14355
|
+
try:
|
|
14356
|
+
_cap = int(os.environ.get("LOKI_REVIEW_MAX_REVIEWERS", "0") or "0")
|
|
14357
|
+
except ValueError:
|
|
14358
|
+
_cap = 0
|
|
14359
|
+
if _cap > 0 and len(reviewers) > _cap:
|
|
14360
|
+
_mandatory_names = {r["name"] for r in mandatory}
|
|
14361
|
+
_keep = [r for r in reviewers if r["name"] in _mandatory_names]
|
|
14362
|
+
for _r in reviewers:
|
|
14363
|
+
if len(_keep) >= _cap:
|
|
14364
|
+
break
|
|
14365
|
+
if _r["name"] not in _mandatory_names:
|
|
14366
|
+
_keep.append(_r)
|
|
14367
|
+
# Never below the mandatory set, even if the cap is set lower than it.
|
|
14368
|
+
reviewers = _keep if len(_keep) >= len(_mandatory_names) else reviewers
|
|
14369
|
+
|
|
14333
14370
|
if os.environ.get("LOKI_REVIEW_REQUIREMENTS_ONLY") == "1":
|
|
14334
14371
|
reviewers = [
|
|
14335
14372
|
reviewer for reviewer in reviewers
|
|
@@ -22839,8 +22876,37 @@ if __name__ == "__main__":
|
|
|
22839
22876
|
log_warn "Invariant gate FAILED ($inv_count consecutive) - CRITICAL/HIGH invariant/property violations (advisory; surfaced to next iteration)"
|
|
22840
22877
|
fi
|
|
22841
22878
|
fi
|
|
22879
|
+
# SKIP THE COUNCIL WHEN A DETERMINISTIC GATE ALREADY FAILED
|
|
22880
|
+
# (LOKI_REVIEW_SKIP_ON_GATE_FAIL, default off).
|
|
22881
|
+
#
|
|
22882
|
+
# Measured: the council costs 31s at 3 reviewers and 280-502s at 6-7.
|
|
22883
|
+
# The gates above cost ~6s COMBINED (static_analysis 5s, security_scan
|
|
22884
|
+
# 1s, lsp_diagnostics 1s, test_suite <1s). When one of them has already
|
|
22885
|
+
# failed, the iteration cannot be accepted no matter what the council
|
|
22886
|
+
# says -- gate_failures is non-empty and feeds the same completion
|
|
22887
|
+
# decision -- so the review is spending 280-502s to produce advice on
|
|
22888
|
+
# code that is already going back for another pass.
|
|
22889
|
+
#
|
|
22890
|
+
# WHAT THIS IS NOT. It does not weaken any gate: a skipped review is
|
|
22891
|
+
# recorded as skipped, never as a PASS, and the failing gate still
|
|
22892
|
+
# blocks exactly as before. It cannot turn a rejection into an
|
|
22893
|
+
# approval -- it only declines to spend five minutes describing a
|
|
22894
|
+
# rejection that is already decided.
|
|
22895
|
+
#
|
|
22896
|
+
# DEFAULT OFF. Review findings are also next-iteration STEERING
|
|
22897
|
+
# (LOKI_INJECT_FINDINGS), so skipping trades some guidance for a large
|
|
22898
|
+
# latency win. That trade is a per-route decision, not a silent
|
|
22899
|
+
# global one.
|
|
22900
|
+
local _skip_review=false
|
|
22901
|
+
if [ "${LOKI_REVIEW_SKIP_ON_GATE_FAIL:-false}" = "true" ] \
|
|
22902
|
+
&& [ -n "${gate_failures:-}" ]; then
|
|
22903
|
+
_skip_review=true
|
|
22904
|
+
fi
|
|
22905
|
+
if [ "$_skip_review" = "true" ]; then
|
|
22906
|
+
log_warn "Code review SKIPPED: deterministic gates already failed (${gate_failures%,}). The iteration is already going back; not spending a full council on it. Unset LOKI_REVIEW_SKIP_ON_GATE_FAIL to always review."
|
|
22907
|
+
emit_stage_complete "code_review" "skipped" "$(date +%s 2>/dev/null)"
|
|
22842
22908
|
# Code review gate (upgraded from advisory, with escalation)
|
|
22843
|
-
|
|
22909
|
+
elif [ "$PHASE_CODE_REVIEW" = "true" ] && [ "$ITERATION_COUNT" -gt 0 ]; then
|
|
22844
22910
|
log_info "Quality gate: code review..."
|
|
22845
22911
|
local _stg_t0=$(date +%s 2>/dev/null); local _stg_ok=pass
|
|
22846
22912
|
if run_code_review; then
|
package/dashboard/__init__.py
CHANGED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# One JSON file to update when a provider ships a model
|
|
2
|
+
|
|
3
|
+
Founder ask (2026-08-01): a simple JSON we define at packaging time, so
|
|
4
|
+
updating for new model releases is easy.
|
|
5
|
+
|
|
6
|
+
## The shape
|
|
7
|
+
|
|
8
|
+
`providers/model_registry.json` -- ONE file, flat, no cross-references. To adopt
|
|
9
|
+
a new model you edit one line.
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"registry_version": "2026-08-01.1",
|
|
14
|
+
"_howto": "Edit a value below and ship. Nothing else needs to change.",
|
|
15
|
+
|
|
16
|
+
"tiers": {
|
|
17
|
+
"frontier": {
|
|
18
|
+
"anthropic": "opus",
|
|
19
|
+
"openai": "gpt-5.6",
|
|
20
|
+
"google": "gemini-3.1-pro-preview"
|
|
21
|
+
},
|
|
22
|
+
"balanced": {
|
|
23
|
+
"anthropic": "sonnet",
|
|
24
|
+
"openai": "gpt-5.6-terra",
|
|
25
|
+
"google": "gemini-3.6-flash"
|
|
26
|
+
},
|
|
27
|
+
"fast": {
|
|
28
|
+
"anthropic": "haiku",
|
|
29
|
+
"openai": "gpt-5.6-luna",
|
|
30
|
+
"google": "gemini-flash-latest"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
"pinned": {
|
|
35
|
+
"_comment": "Optional. Set to override an alias with an exact snapshot.",
|
|
36
|
+
"anthropic": {},
|
|
37
|
+
"openai": {},
|
|
38
|
+
"google": {}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
That is the whole contract. Three tiers x three providers.
|
|
44
|
+
|
|
45
|
+
## The one design decision that matters: ALIAS, not snapshot
|
|
46
|
+
|
|
47
|
+
The `anthropic` column holds `opus` / `sonnet` / `haiku`, not
|
|
48
|
+
`claude-opus-5` / `claude-sonnet-5` / `claude-haiku-4-5`.
|
|
49
|
+
|
|
50
|
+
**Verified against the live CLI on 2026-08-01:**
|
|
51
|
+
|
|
52
|
+
| passed | resolves to | note |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `opus` | `claude-opus-5` | tracks latest automatically |
|
|
55
|
+
| `best` | `claude-fable-5` | Anthropic's most capable GA model |
|
|
56
|
+
| `haiku` | `claude-haiku-4-5-20251001` | |
|
|
57
|
+
| `claude-haiku-4-6` | **REJECTED** | "may not exist or you may not have access" |
|
|
58
|
+
|
|
59
|
+
Two facts fall out of that table, and both argue for aliases:
|
|
60
|
+
|
|
61
|
+
1. **Aliases self-update.** When Anthropic ships Opus 6, `opus` follows it with
|
|
62
|
+
zero edits to this file. A snapshot id would need a release to track it --
|
|
63
|
+
which is exactly how our catalog ended up pinned to `claude-opus-4-8` while
|
|
64
|
+
Opus 5 shipped (fixed in v8.31.0).
|
|
65
|
+
2. **Snapshot ids are account-scoped.** `claude-haiku-4-6` may exist on the API
|
|
66
|
+
and still be unreachable on a given account/CLI. Hardcoding it ships a
|
|
67
|
+
broken default to whoever lacks access.
|
|
68
|
+
|
|
69
|
+
That second point is not theoretical. We already have a scar:
|
|
70
|
+
`tests/test-codex-model-trusted.sh` records that pinning `gpt-5.3-codex` broke
|
|
71
|
+
**every ChatGPT-account user**, because codex-cli rejects it on that tier -- and
|
|
72
|
+
Codex ships free with every ChatGPT plan. The safe landing spot was "send no
|
|
73
|
+
model and let the provider choose."
|
|
74
|
+
|
|
75
|
+
**Rule: prefer a provider alias. Use an exact id only in `pinned`, only
|
|
76
|
+
deliberately.**
|
|
77
|
+
|
|
78
|
+
## Why `pinned` exists
|
|
79
|
+
|
|
80
|
+
Anthropic's docs are explicit that Claude 4.6-generation dateless identifiers
|
|
81
|
+
are still **pinned snapshots, not evergreen pointers**. And Claude Code's
|
|
82
|
+
`best` / `opus` / `sonnet` are *Claude Code routing aliases* -- not a portable
|
|
83
|
+
contract in the raw Messages API.
|
|
84
|
+
|
|
85
|
+
So: aliases are right for the CLI providers we drive, and `pinned` is the escape
|
|
86
|
+
hatch for anyone who needs reproducibility or is calling an API directly.
|
|
87
|
+
Empty by default.
|
|
88
|
+
|
|
89
|
+
## What "frontier" maps to for Anthropic
|
|
90
|
+
|
|
91
|
+
`best` resolves to `claude-fable-5` today, and Anthropic positions Fable as most
|
|
92
|
+
capable generally, with `claude-opus-5` aimed specifically at complex agentic
|
|
93
|
+
coding and enterprise work.
|
|
94
|
+
|
|
95
|
+
**We map `frontier` -> `opus`, not `best`.** Our workload IS agentic coding, and
|
|
96
|
+
`fable` is advisory-only in this codebase: the runner collapses it to opus, so
|
|
97
|
+
offering it as an execution model would be a cost surprise. That reasoning
|
|
98
|
+
predates this file and is unchanged.
|
|
99
|
+
|
|
100
|
+
## What this replaces, and what it does not
|
|
101
|
+
|
|
102
|
+
`providers/model_catalog.json` stays. It carries per-provider metadata this file
|
|
103
|
+
deliberately does not (validation prefixes, tier fallbacks, aider's litellm
|
|
104
|
+
strings, the `models[]` ordering that the resolver depends on).
|
|
105
|
+
|
|
106
|
+
`model_registry.json` is the **editable surface**: the file a human opens when a
|
|
107
|
+
provider ships something. The catalog becomes derived where they overlap, and
|
|
108
|
+
`tests/test-model-catalog-single-source.sh` already fails when derived mirrors
|
|
109
|
+
disagree with their source -- that mechanism extends to cover this.
|
|
110
|
+
|
|
111
|
+
## Rollout, matching the lifecycle in the founder's note
|
|
112
|
+
|
|
113
|
+
The note's recommended lifecycle is right, and one step already exists here:
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
provider release detected <- tools/probe-model-catalog.py (exists, reads live docs)
|
|
117
|
+
v
|
|
118
|
+
add as frontier candidate <- edit model_registry.json
|
|
119
|
+
v
|
|
120
|
+
run coding-agent eval suite <- benchmarks/ (exists)
|
|
121
|
+
v
|
|
122
|
+
canary <- NOT built; needs traffic splitting we do not have
|
|
123
|
+
v
|
|
124
|
+
promote alias <- edit one line
|
|
125
|
+
v
|
|
126
|
+
keep previous as fallback <- pinned{} holds the old id
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Honest gap:** we have no traffic-splitting layer, so 5% canary is not
|
|
130
|
+
implementable today. Do not put it in a release note as though it were.
|
|
131
|
+
Aliases blunt the need -- the provider is the one rolling the model forward,
|
|
132
|
+
and our eval suite plus the previous id in `pinned` is the realistic control.
|
|
133
|
+
|
|
134
|
+
## Resolution order (must stay identical on both routes)
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
LOKI_<PROVIDER>_MODEL (trusted verbatim -- fine-tunes, org models)
|
|
138
|
+
-> pinned[provider][tier] (deliberate snapshot)
|
|
139
|
+
-> tiers[tier][provider] (the alias -- the normal path)
|
|
140
|
+
-> provider default (may legitimately be EMPTY: see codex/ChatGPT)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The last line is load-bearing. Empty means "send no `--model` and let the
|
|
144
|
+
provider pick," which is correct whenever we cannot know an id is valid for that
|
|
145
|
+
account. Never replace it with a guess.
|
|
146
|
+
|
|
147
|
+
## Acceptance
|
|
148
|
+
|
|
149
|
+
- Adding a model is a one-line edit to `model_registry.json`.
|
|
150
|
+
- `tests/test-model-catalog-current-flagship.sh` (v8.31.0) already fails when a
|
|
151
|
+
tier points at a superseded same-family model; extend it to this file.
|
|
152
|
+
- A mutation flipping any alias back to a hardcoded snapshot must turn a test
|
|
153
|
+
red.
|
|
154
|
+
- No test may assert an exact snapshot id that this account cannot dispatch --
|
|
155
|
+
the `claude-haiku-4-6` result above is the reason.
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Fastest First-Pass Completion: measured plan
|
|
2
|
+
|
|
3
|
+
Goal (founder, 2026-08-01): **fastest first-pass full completion** -- highest
|
|
4
|
+
quality output, no waiting through a second iteration, faster than Cursor /
|
|
5
|
+
Cognition / Replit on the axis a user actually feels.
|
|
6
|
+
|
|
7
|
+
This plan is built on measurement first, competitor research second, and it
|
|
8
|
+
DISCARDS the intuition I started with.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. What the competition actually does (researched, not assumed)
|
|
13
|
+
|
|
14
|
+
| Vendor | Speed mechanism | Reachable for us? |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| **Cursor** | Composer: in-house MoE model, ~250 tok/s (~4x GPT-5/Sonnet). MXFP8 training, no post-train quant. Compaction-in-the-loop RL cuts context errors 50%. | **No.** Custom frontier model. |
|
|
17
|
+
| **Cognition** | SWE-1.6 at ~950 tok/s; SWE-bench 51.5%. | **No.** Custom model. |
|
|
18
|
+
| **Replit** | Agent 3: ~2 min to visual preview, ~10 min to first app version. Design Mode <2 min. 2-3x gains across 2025. | **Partly.** Their edge is product/lifecycle, not model. |
|
|
19
|
+
|
|
20
|
+
**The strategic conclusion.** Cursor and Cognition bought speed by TRAINING
|
|
21
|
+
THEIR OWN MODELS. We cannot copy that and should stop pretending the gap is
|
|
22
|
+
closable that way. Replit's edge is time-to-first-visible-thing, which IS
|
|
23
|
+
reachable, because it is a product and lifecycle property.
|
|
24
|
+
|
|
25
|
+
The industry-wide numbers that matter for us, from the latency research:
|
|
26
|
+
|
|
27
|
+
- **Tool execution is 35-61% of total agent request time.** Harness, not model.
|
|
28
|
+
- Parallel tool calling / speculative execution deliver **2-5x latency
|
|
29
|
+
reduction while preserving correctness**.
|
|
30
|
+
- Prompt caching turns repeated-prefix attention from O(n^2) to O(n).
|
|
31
|
+
|
|
32
|
+
That 35-61% is our lane. It is won by architecture, and it does not require a
|
|
33
|
+
frontier lab.
|
|
34
|
+
|
|
35
|
+
## 2. What we actually cost, MEASURED (this is the surprise)
|
|
36
|
+
|
|
37
|
+
Real `stage_complete` events from builds on this machine (n=35):
|
|
38
|
+
|
|
39
|
+
| stage | n | median s | max s | total s |
|
|
40
|
+
|---|---:|---:|---:|---:|
|
|
41
|
+
| **code_review** | 3 | **281** | **504** | **1055** |
|
|
42
|
+
| static_analysis | 5 | 5 | 14 | 26 |
|
|
43
|
+
| security_scan | 5 | 1 | 2 | 4 |
|
|
44
|
+
| lsp_diagnostics | 4 | 1 | 1 | 2 |
|
|
45
|
+
| test_suite | 4 | 0 | 1 | 1 |
|
|
46
|
+
| mutation_integrity | 4 | 0 | 1 | 1 |
|
|
47
|
+
| mock_integrity | 4 | 0 | 0 | 0 |
|
|
48
|
+
| doc_coverage | 3 | 0 | 0 | 0 |
|
|
49
|
+
| magic_debate | 3 | 0 | 0 | 0 |
|
|
50
|
+
| **TOTAL** | | | | **1089** |
|
|
51
|
+
|
|
52
|
+
**`code_review` is 97% of all measured gate time.** Everything else combined is
|
|
53
|
+
34 seconds.
|
|
54
|
+
|
|
55
|
+
### Two intuitions this killed
|
|
56
|
+
|
|
57
|
+
**First:** I was about to propose parallelizing the seven sequential gates at
|
|
58
|
+
`run.sh:22616-22980`. They ARE sequential and mostly independent. The change
|
|
59
|
+
would have been clean, defensible, and worth **about 20 seconds**.
|
|
60
|
+
|
|
61
|
+
**Second, and worse:** I then proposed parallelizing the reviewer council --
|
|
62
|
+
which was **already parallel**. I had grepped the wrong line range, got no
|
|
63
|
+
match, and treated that silence as evidence. A plan whose headline item was a
|
|
64
|
+
no-op.
|
|
65
|
+
|
|
66
|
+
Both were caught by going back to data instead of trusting the story. The
|
|
67
|
+
standing rule for this document:
|
|
68
|
+
|
|
69
|
+
> **No optimization ships without a before-number from this table, and no
|
|
70
|
+
> claim about how the code behaves ships without reading the code that does
|
|
71
|
+
> it.**
|
|
72
|
+
|
|
73
|
+
An absent grep match is not evidence of absence -- it is evidence the grep did
|
|
74
|
+
not match.
|
|
75
|
+
|
|
76
|
+
### Where the real time goes
|
|
77
|
+
|
|
78
|
+
Code review dominates, and the driver is **council size**, not sequential
|
|
79
|
+
dispatch (see the correction in P0 -- my first reading of this was wrong).
|
|
80
|
+
|
|
81
|
+
Measured: 3 reviewers finish in 31s; 6-7 reviewers take 177-502s. The council
|
|
82
|
+
is already concurrent, so what grows is the max-of-N tail plus contention on a
|
|
83
|
+
single provider.
|
|
84
|
+
|
|
85
|
+
This explains the founder's "21 minutes for a simple GitHub issue" better than
|
|
86
|
+
any other measurement taken today: a scoped issue was drawing a 7-member
|
|
87
|
+
council containing two overlapping security reviewers.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 3. The plan, ranked by measured seconds returned
|
|
92
|
+
|
|
93
|
+
### P0 -- CORRECTED: the council is ALREADY parallel. The cost is its SIZE.
|
|
94
|
+
|
|
95
|
+
**This section originally claimed reviewers ran sequentially and proposed
|
|
96
|
+
parallelizing them. That was wrong, and the correction is recorded here rather
|
|
97
|
+
than quietly edited out.**
|
|
98
|
+
|
|
99
|
+
`run_code_review` forks every reviewer with `) &` (run.sh:14803), collects PIDs,
|
|
100
|
+
and `wait`s on each (run.sh:14880). It has been parallel all along. My first
|
|
101
|
+
grep searched the wrong line range, returned nothing, and I read that silence as
|
|
102
|
+
proof of absence -- the same mistake class this codebase has been punishing all
|
|
103
|
+
session.
|
|
104
|
+
|
|
105
|
+
**What the data actually says.** Pairing `code_review_start` with
|
|
106
|
+
`code_review_complete` across every recorded review:
|
|
107
|
+
|
|
108
|
+
| reviewers | seconds | verdict |
|
|
109
|
+
|---:|---:|---|
|
|
110
|
+
| 7 | 502 | 0 pass / 7 fail |
|
|
111
|
+
| 7 | 280 | 1 pass / 6 fail |
|
|
112
|
+
| 6 | 177 | 0 pass / 5 fail |
|
|
113
|
+
| **3** | **31** | 2 pass / 1 fail |
|
|
114
|
+
|
|
115
|
+
**3 reviewers = 31s. 7 reviewers = 280-502s.** Roughly 2x the council for 9-16x
|
|
116
|
+
the wall clock. Since dispatch is already concurrent, that superlinearity is not
|
|
117
|
+
the count itself -- it is that a larger council pulls in slower reviewers and
|
|
118
|
+
contends for the same provider, so the max-of-N tail dominates.
|
|
119
|
+
|
|
120
|
+
**And the 7-member council is partly redundant:**
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
architecture-strategist, maintainer-mergeability,
|
|
124
|
+
security-sentinel, review-security, <- TWO security reviewers
|
|
125
|
+
performance-oracle, eng-qa, dependency-analyst
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`security-sentinel` and `review-security` overlap. `eng-qa` and
|
|
129
|
+
`dependency-analyst` are appended agents, not part of the sized battery.
|
|
130
|
+
|
|
131
|
+
**The real P0, in priority order:**
|
|
132
|
+
|
|
133
|
+
1. **Deduplicate overlapping reviewers.** Two security reviewers on one diff is
|
|
134
|
+
paying the tail cost twice for one signal. Collapse by mandate, not by name.
|
|
135
|
+
2. **Cap the effective council for scoped changes.** The tier map is
|
|
136
|
+
`{simple: 2, standard: 2, complex: 4}` specialists + 2 mandatory. Appended
|
|
137
|
+
agents bypass that sizing entirely, which is how 4 becomes 7. Bound the
|
|
138
|
+
TOTAL, not just the specialist slots.
|
|
139
|
+
3. **Bound the tail, not the mean.** One slow reviewer sets the whole council's
|
|
140
|
+
latency. A per-reviewer deadline that records a non-vote (never a silent
|
|
141
|
+
pass) converts a 502s worst case into a bounded one.
|
|
142
|
+
|
|
143
|
+
Expected: the 6-7 member case moves toward the measured 3-member behaviour
|
|
144
|
+
(31s) for scoped work, while `complex` keeps its deeper battery.
|
|
145
|
+
|
|
146
|
+
**Fail-safe direction is load-bearing:** a dropped or deadlined reviewer must
|
|
147
|
+
count as a NON-VOTE exactly as today, never as a pass. Shrinking a council must
|
|
148
|
+
never be able to manufacture approval. Guard with a test asserting the verdict
|
|
149
|
+
is identical for the same fixture at any council size, and that a deadlined
|
|
150
|
+
reviewer never contributes a PASS.
|
|
151
|
+
|
|
152
|
+
### P1 -- Do not run the full council on iteration 1 of a scoped change
|
|
153
|
+
|
|
154
|
+
The 8-gate council exists to catch regressions in a large build. On a scoped
|
|
155
|
+
GitHub-issue fix, running a 3-reviewer council before the change is even
|
|
156
|
+
verified is spending 281s to review something a test run would disprove in 1s.
|
|
157
|
+
|
|
158
|
+
- Order: cheap deterministic gates FIRST (test_suite, static_analysis,
|
|
159
|
+
lsp_diagnostics -- 6s combined), council only if those pass.
|
|
160
|
+
- A failing test means the council would have rejected anyway; running it first
|
|
161
|
+
is strictly wasted wall-clock.
|
|
162
|
+
- Expected: on a failing first pass, ~281s saved outright.
|
|
163
|
+
|
|
164
|
+
### P2 -- Time-to-first-signal (the Replit lesson)
|
|
165
|
+
|
|
166
|
+
Replit shows a visual preview in ~2 minutes. We show nothing until an iteration
|
|
167
|
+
completes. Even when our total time is competitive, the FELT time is worse.
|
|
168
|
+
|
|
169
|
+
- Emit a first-signal event as soon as the agent's first file write lands.
|
|
170
|
+
- `.loki/app-runner/first-preview.json` already exists (write-once, bash route)
|
|
171
|
+
-- surface it, and extend to the non-preview case as "first artifact".
|
|
172
|
+
- This is perception, not throughput, and it is cheap.
|
|
173
|
+
|
|
174
|
+
### P3 -- First-pass correctness (the actual "no second iteration" ask)
|
|
175
|
+
|
|
176
|
+
Research finding: success now hinges on **specification quality and dynamic
|
|
177
|
+
context**, not static upfront planning. Notably, auto-generated context files
|
|
178
|
+
REDUCED success ~3% while human-written ones improved it ~4%, both raising cost
|
|
179
|
+
20%+. So "generate a big context file" is measurably the wrong move.
|
|
180
|
+
|
|
181
|
+
What the evidence supports:
|
|
182
|
+
- ACE (ICLR 2026): generate -> reflect -> curate as an evolving context loop:
|
|
183
|
+
**+10.6% on coding benchmarks**.
|
|
184
|
+
- We already have the seam: `LOKI_INJECT_FINDINGS` feeds structured per-finding
|
|
185
|
+
records into the next iteration.
|
|
186
|
+
- The lever is making iteration 1's prompt carry what iteration 2 would have
|
|
187
|
+
learned -- which the existing first-pass-excellence work began and which
|
|
188
|
+
measured 2.8x cheaper with correctness held.
|
|
189
|
+
|
|
190
|
+
**Do not** add a static generated context file. The data says it hurts.
|
|
191
|
+
|
|
192
|
+
### P4 -- Prompt-cache discipline (already partly built, verify it holds)
|
|
193
|
+
|
|
194
|
+
`[CACHE_BREAKPOINT]` splits a cache-stable prefix from a volatile tail. Cache
|
|
195
|
+
reads price at 0.1x input. Any always-on instruction added to the wrong side
|
|
196
|
+
busts the cache every iteration.
|
|
197
|
+
|
|
198
|
+
- Add a regression test asserting no volatile content crosses the breakpoint.
|
|
199
|
+
- This is a cost lever primarily, and a TTFT lever secondarily.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 4. What we do NOT do
|
|
204
|
+
|
|
205
|
+
- **Do not train a model.** Cursor and Cognition's speed is bought with custom
|
|
206
|
+
MoE models at 250-950 tok/s. That is not a gap we close with harness work,
|
|
207
|
+
and claiming otherwise would be dishonest.
|
|
208
|
+
- **Do not parallelize the seven cheap gates as a headline.** Measured worth:
|
|
209
|
+
~20s. Do it opportunistically inside P1's reordering, never sold as the win.
|
|
210
|
+
- **Do not add static generated context files.** Measured -3% success, +20%
|
|
211
|
+
cost.
|
|
212
|
+
|
|
213
|
+
## 5. How we know it worked
|
|
214
|
+
|
|
215
|
+
Every item ships with a before/after from the same `stage_complete` telemetry
|
|
216
|
+
that produced the table above. The acceptance number for the founder's
|
|
217
|
+
complaint:
|
|
218
|
+
|
|
219
|
+
> a scoped GitHub issue completes in **under 5 minutes**, first pass,
|
|
220
|
+
> with the council verdict intact.
|
|
221
|
+
|
|
222
|
+
Current measured critical path for that case is dominated by 281s of
|
|
223
|
+
sequential code review. P0 + P1 target exactly that.
|
|
224
|
+
|
|
225
|
+
## 6. Honest competitive position after this plan
|
|
226
|
+
|
|
227
|
+
- **vs Cursor** on raw interactive latency: still behind. Different category.
|
|
228
|
+
- **vs Replit** on time-to-first-visible: reachable with P2.
|
|
229
|
+
- **vs Cognition** on trust: ahead, and that is the moat -- the Evidence
|
|
230
|
+
Receipt, now that the gates behind it actually run (v8.24.0-v8.31.0).
|
|
231
|
+
|
|
232
|
+
The wedge is **verified-and-fast**, not fastest-in-absolute. We should say that
|
|
233
|
+
plainly rather than claim a speed crown we cannot hold.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
Sources: Cursor Composer blog, VentureBeat Composer coverage, Cognition
|
|
238
|
+
SWE-1.6 reporting, Replit Agent 3 reviews, Zylos speculative-execution/parallel
|
|
239
|
+
tool-calling research, ACE (ICLR 2026), 2026 context-engineering surveys.
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var h_=Object.create;var{getPrototypeOf:v_,defineProperty:rK,getOwnPropertyNames:g_}=Object;var m_=Object.prototype.hasOwnProperty;function u_(Z){return this[Z]}var p_,d_,c_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?p_??=new WeakMap:d_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?h_(v_(Z)):{};let K=X||!Z||!Z.__esModule?rK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of g_(Z))if(!m_.call(K,$))rK(K,$,{get:u_.bind(Z,$),enumerable:!0});if(Y)J.set(Z,K);return K};var qQ=(Z,X)=>()=>(X||Z((X={exports:{}}).exports,X),X.exports);var l_=(Z)=>Z;function i_(Z,X){this[Z]=l_.bind(null,X)}var l0=(Z,X)=>{for(var Q in X)rK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:i_.bind(X,Q)})};var p=(Z,X)=>()=>(Z&&(X=Z(Z=0)),X);var e0=import.meta.require;var kO={};l0(kO,{lokiDir:()=>j0,homeLokiDir:()=>P4,findRepoRootForVersion:()=>eK,REPO_ROOT:()=>r0});import{resolve as n7,dirname as tK}from"path";import{fileURLToPath as a_}from"url";import{existsSync as GQ}from"fs";import{homedir as s_}from"os";function n_(){let Z=RO;for(let X=0;X<6;X++){if(GQ(n7(Z,"VERSION"))&&GQ(n7(Z,"autonomy/run.sh")))return Z;let Q=tK(Z);if(Q===Z)break;Z=Q}return n7(RO,"..","..","..")}function eK(Z){let X=Z;for(let Q=0;Q<6;Q++){if(GQ(n7(X,"VERSION"))&&GQ(n7(X,"autonomy/run.sh")))return X;let Y=tK(X);if(Y===X)break;X=Y}return n7(Z,"..","..","..")}function j0(){return process.env.LOKI_DIR??n7(process.cwd(),".loki")}function P4(){return n7(s_(),".loki")}var RO,r0;var G8=p(()=>{RO=tK(a_(import.meta.url));r0=n_()});import{readFileSync as o_}from"fs";import{resolve as r_,dirname as t_}from"path";import{fileURLToPath as e_}from"url";function f3(){if(h5!==null)return h5;let Z="8.
|
|
2
|
+
var h_=Object.create;var{getPrototypeOf:v_,defineProperty:rK,getOwnPropertyNames:g_}=Object;var m_=Object.prototype.hasOwnProperty;function u_(Z){return this[Z]}var p_,d_,c_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?p_??=new WeakMap:d_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?h_(v_(Z)):{};let K=X||!Z||!Z.__esModule?rK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of g_(Z))if(!m_.call(K,$))rK(K,$,{get:u_.bind(Z,$),enumerable:!0});if(Y)J.set(Z,K);return K};var qQ=(Z,X)=>()=>(X||Z((X={exports:{}}).exports,X),X.exports);var l_=(Z)=>Z;function i_(Z,X){this[Z]=l_.bind(null,X)}var l0=(Z,X)=>{for(var Q in X)rK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:i_.bind(X,Q)})};var p=(Z,X)=>()=>(Z&&(X=Z(Z=0)),X);var e0=import.meta.require;var kO={};l0(kO,{lokiDir:()=>j0,homeLokiDir:()=>P4,findRepoRootForVersion:()=>eK,REPO_ROOT:()=>r0});import{resolve as n7,dirname as tK}from"path";import{fileURLToPath as a_}from"url";import{existsSync as GQ}from"fs";import{homedir as s_}from"os";function n_(){let Z=RO;for(let X=0;X<6;X++){if(GQ(n7(Z,"VERSION"))&&GQ(n7(Z,"autonomy/run.sh")))return Z;let Q=tK(Z);if(Q===Z)break;Z=Q}return n7(RO,"..","..","..")}function eK(Z){let X=Z;for(let Q=0;Q<6;Q++){if(GQ(n7(X,"VERSION"))&&GQ(n7(X,"autonomy/run.sh")))return X;let Y=tK(X);if(Y===X)break;X=Y}return n7(Z,"..","..","..")}function j0(){return process.env.LOKI_DIR??n7(process.cwd(),".loki")}function P4(){return n7(s_(),".loki")}var RO,r0;var G8=p(()=>{RO=tK(a_(import.meta.url));r0=n_()});import{readFileSync as o_}from"fs";import{resolve as r_,dirname as t_}from"path";import{fileURLToPath as e_}from"url";function f3(){if(h5!==null)return h5;let Z="8.34.0";if(typeof Z==="string"&&Z.length>0)return h5=Z,h5;try{let X=t_(e_(import.meta.url)),Q=eK(X);h5=o_(r_(Q,"VERSION"),"utf-8").trim()}catch{h5="unknown"}return h5}var h5=null;var HQ=p(()=>{G8()});var bO={};l0(bO,{runOrThrow:()=>Of,run:()=>E0,readStreamCapped:()=>UQ,commandVersion:()=>Af,commandExists:()=>X9,ShellError:()=>Z$,MAX_STDOUT_BYTES:()=>yO});async function UQ(Z,X=yO){let Q=Z.getReader(),Y=new TextDecoder,J="",z=0;try{while(z<X){let{done:K,value:$}=await Q.read();if(K)break;if(!$)continue;if(z+=$.byteLength,z>X){let W=$.byteLength-(z-X);J+=Y.decode($.subarray(0,W),{stream:!0});break}J+=Y.decode($,{stream:!0})}J+=Y.decode()}finally{try{await Q.cancel()}catch{}Q.releaseLock()}return J}async function E0(Z,X={}){let Q=Bun.spawn({cmd:[...Z],stdout:"pipe",stderr:"pipe",env:X.env?{...process.env,...X.env}:process.env,cwd:X.cwd}),Y,J;if(X.timeoutMs&&X.timeoutMs>0)Y=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}J=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},X.timeoutMs);try{let[z,K,$]=await Promise.all([UQ(Q.stdout),new Response(Q.stderr).text(),Q.exited]);return{stdout:z,stderr:K,exitCode:$}}finally{if(Y)clearTimeout(Y);if(J)clearTimeout(J)}}async function Of(Z,X={}){let Q=await E0(Z,X);if(Q.exitCode!==0)throw new Z$(`command failed (${Q.exitCode}): ${Z.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function X9(Z){let X=Lf(Z),Q=await E0(["sh","-c",`command -v ${X}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Lf(Z){if(!/^[A-Za-z0-9._/-]+$/.test(Z))throw Error(`refused to shell-escape suspect token: ${Z}`);return Z}async function Af(Z,X="--version"){if(!await X9(Z))return null;let Y=await E0([Z,X],{timeoutMs:5000});if(Y.exitCode!==0)return null;return((Y.stdout||Y.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var yO=16777216,Z$;var x9=p(()=>{Z$=class Z$ extends Error{message;exitCode;stdout;stderr;constructor(Z,X,Q,Y){super(Z);this.message=Z;this.exitCode=X;this.stdout=Q;this.stderr=Y;this.name="ShellError"}}});function o7(Z){return jf?"":Z}var jf,L0,k8,p0,ZV0,i0,H8,Q9,v;var S6=p(()=>{jf=(process.env.NO_COLOR??"").length>0;L0=o7("\x1B[0;31m"),k8=o7("\x1B[0;32m"),p0=o7("\x1B[1;33m"),ZV0=o7("\x1B[0;34m"),i0=o7("\x1B[0;36m"),H8=o7("\x1B[1m"),Q9=o7("\x1B[2m"),v=o7("\x1B[0m")});import{existsSync as xf}from"fs";async function E7(){if(k4!==void 0)return k4;let Z="/opt/homebrew/bin/python3.12";if(xf(Z))return k4=Z,Z;let X=await X9("python3.12");if(X)return k4=X,X;let Q=await X9("python3");return k4=Q,Q}async function Y7(Z,X={}){let Q=await E7();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return E0([Q,"-c",Z],X)}var k4;var r7=p(()=>{x9()});var ZL={};l0(ZL,{runStatus:()=>Yh});import{existsSync as Y9,readFileSync as v3,readdirSync as iO,statSync as aO}from"fs";import{resolve as h8,basename as sf}from"path";import{homedir as nf}from"os";function sO(Z){let X=Math.trunc(Z);if(X>=1e6)return`${(Math.trunc(X/1e6*10)/10).toFixed(1)}M`;if(X>=1000)return`${(Math.trunc(X/1000*10)/10).toFixed(1)}K`;return String(X)}function nO(Z,X,Q){if(X===0)return null;let Y=Math.trunc(Z*100/X),J=Math.trunc(Z*NQ/X);if(J>NQ)J=NQ;let z=NQ-J,K=k8;if(Y>=80)K=L0;else if(Y>=50)K=p0;let $="=".repeat(Math.max(0,J))+" ".repeat(Math.max(0,z)),W=sO(Z),V=sO(X);return` ${H8}${Q}${v} ${K}[${$}]${v} ${Y}% (${W} / ${V})`}async function rf(){if(await X9("jq"))return!0;return process.stdout.write(`${L0}Error: jq is required but not installed.${v}
|
|
3
3
|
`),process.stdout.write(`Install with:
|
|
4
4
|
`),process.stdout.write(` brew install jq (macOS)
|
|
5
5
|
`),process.stdout.write(` apt install jq (Debian/Ubuntu)
|
|
@@ -1222,4 +1222,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
1222
1222
|
`),2}case"start":{let{runStart:Y}=await Promise.resolve().then(() => (b_(),y_));return Y(Q)}default:return process.stderr.write(`Unknown command: ${X}
|
|
1223
1223
|
`),process.stderr.write(__),2}}cO();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var fW0=await _W0(Bun.argv.slice(2));process.exit(fW0);
|
|
1224
1224
|
|
|
1225
|
-
//# debugId=
|
|
1225
|
+
//# debugId=651C52085A3FC1C964756E2164756E21
|
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loki-mode",
|
|
3
3
|
"mcpName": "io.github.asklokesh/loki-mode",
|
|
4
|
-
"version": "8.
|
|
4
|
+
"version": "8.34.0",
|
|
5
5
|
"description": "Loki Mode by Autonomi. Autonomous spec-to-product system: takes a PRD, GitHub issue, OpenAPI/JSON/YAML, or one-line brief to a deployed app via the RARV-C closure loop with 8 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider).",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "loki-mode",
|
|
4
4
|
"displayName": "Loki Mode",
|
|
5
|
-
"version": "8.
|
|
5
|
+
"version": "8.34.0",
|
|
6
6
|
"description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 8 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Autonomi",
|