loki-guardrails 0.1.0__tar.gz
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.
- loki_guardrails-0.1.0/.gitignore +24 -0
- loki_guardrails-0.1.0/LICENSE +24 -0
- loki_guardrails-0.1.0/PKG-INFO +237 -0
- loki_guardrails-0.1.0/README.md +214 -0
- loki_guardrails-0.1.0/benchmarks/README.md +161 -0
- loki_guardrails-0.1.0/loki.py +8017 -0
- loki_guardrails-0.1.0/packaging/__init__.py +5 -0
- loki_guardrails-0.1.0/pyproject.toml +99 -0
- loki_guardrails-0.1.0/shim/loki-omp.ts +32 -0
- loki_guardrails-0.1.0/shim/loki.ts +101 -0
- loki_guardrails-0.1.0/templates/.credo.exs +29 -0
- loki_guardrails-0.1.0/templates/.golangci.yml +38 -0
- loki_guardrails-0.1.0/templates/.oxlintrc.json +66 -0
- loki_guardrails-0.1.0/templates/.ruff.toml +13 -0
- loki_guardrails-0.1.0/templates/claude-settings.fragment.json +39 -0
- loki_guardrails-0.1.0/templates/codex-hooks.json +40 -0
- loki_guardrails-0.1.0/templates/factory-hooks.json +37 -0
- loki_guardrails-0.1.0/templates/loki.json +12 -0
- loki_guardrails-0.1.0/templates/loki.yml +70 -0
- loki_guardrails-0.1.0/tests/__init__.py +21 -0
- loki_guardrails-0.1.0/tests/helpers.py +36 -0
- loki_guardrails-0.1.0/tests/loki-omp.test.ts +22 -0
- loki_guardrails-0.1.0/tests/loki-shim.test.ts +188 -0
- loki_guardrails-0.1.0/tests/test_admission.py +122 -0
- loki_guardrails-0.1.0/tests/test_analyzers.py +872 -0
- loki_guardrails-0.1.0/tests/test_benchmark_contracts.py +51 -0
- loki_guardrails-0.1.0/tests/test_cli.py +72 -0
- loki_guardrails-0.1.0/tests/test_competitive_features.py +206 -0
- loki_guardrails-0.1.0/tests/test_comprehensive_benchmark.py +336 -0
- loki_guardrails-0.1.0/tests/test_content_rules.py +905 -0
- loki_guardrails-0.1.0/tests/test_daemon.py +141 -0
- loki_guardrails-0.1.0/tests/test_dependencies.py +217 -0
- loki_guardrails-0.1.0/tests/test_elixir_analysis.py +145 -0
- loki_guardrails-0.1.0/tests/test_installed_hooks.py +145 -0
- loki_guardrails-0.1.0/tests/test_language_commands.py +219 -0
- loki_guardrails-0.1.0/tests/test_language_rulesets.py +145 -0
- loki_guardrails-0.1.0/tests/test_prewrite_content.py +334 -0
- loki_guardrails-0.1.0/tests/test_python_ast.py +177 -0
- loki_guardrails-0.1.0/tests/test_repository_guardrails.py +374 -0
- loki_guardrails-0.1.0/tests/test_scan_installer.py +291 -0
- loki_guardrails-0.1.0/tests/test_shell_permissions.py +264 -0
- loki_guardrails-0.1.0/tests/test_slop.py +397 -0
- loki_guardrails-0.1.0/tests/test_sobelow_delta.py +230 -0
- loki_guardrails-0.1.0/tests/test_utilities.py +205 -0
- loki_guardrails-0.1.0/vendor/anti-slop/LICENSE +21 -0
- loki_guardrails-0.1.0/vendor/anti-slop/index.ts +41 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-chained-type-assertions.ts +77 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-conditional-empty-object-spread.ts +49 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-known-value-widening.ts +247 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-module-mocking.ts +91 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-object-parameters.ts +126 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-reflect-apply.ts +28 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-reflect-get.ts +28 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-runtime-typeof.ts +67 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-shape-in-symbol-names.ts +39 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-unknown-parameters.ts +83 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-unknown-returns.ts +115 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-unknown-type-aliases.ts +70 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-unsafe-dictionary-type.ts +134 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/no-widen-then-assert.ts +366 -0
- loki_guardrails-0.1.0/vendor/anti-slop/rules/require-safety-comment-for-type-assertion.ts +62 -0
- loki_guardrails-0.1.0/vendor/anti-slop/shared/dictionary-types.ts +502 -0
- loki_guardrails-0.1.0/vendor/anti-slop/shared/lexical-type-parameters.ts +61 -0
- loki_guardrails-0.1.0/vendor/anti-slop/shared/reflect-method.ts +35 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.coverage
|
|
2
|
+
.mutmut-cache/
|
|
3
|
+
.pytest_cache/
|
|
4
|
+
.venv/
|
|
5
|
+
mutants/
|
|
6
|
+
__pycache__/
|
|
7
|
+
.ruff_cache/
|
|
8
|
+
node_modules/
|
|
9
|
+
|
|
10
|
+
# Local agent installations, session state, and working notes.
|
|
11
|
+
/.agents/
|
|
12
|
+
/.claude/
|
|
13
|
+
/.completion-loop/
|
|
14
|
+
/handoff.md
|
|
15
|
+
/research.md
|
|
16
|
+
/research-addendum.md
|
|
17
|
+
/skills-lock.json
|
|
18
|
+
/artifacts/tmp/
|
|
19
|
+
|
|
20
|
+
# Local credentials.
|
|
21
|
+
.env
|
|
22
|
+
.env.*
|
|
23
|
+
!.env.example
|
|
24
|
+
dist/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bryan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
The vendored anti-slop Oxlint plugin in vendor/anti-slop is MIT licensed by
|
|
24
|
+
Dillon Mulroy; see vendor/anti-slop/LICENSE.
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: loki-guardrails
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Deterministic guardrails for AI coding agents: blocks unsafe edits before they land
|
|
5
|
+
Project-URL: Homepage, https://github.com/alfredosdpiii/loki
|
|
6
|
+
Project-URL: Documentation, https://github.com/alfredosdpiii/loki/blob/main/docs/reference.md
|
|
7
|
+
Project-URL: Issues, https://github.com/alfredosdpiii/loki/issues
|
|
8
|
+
Author: Bryan
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
License-File: vendor/anti-slop/LICENSE
|
|
12
|
+
Keywords: ai-agents,claude-code,codex,guardrails,hooks,linting,static-analysis
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: MacOS
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
<div align="center">
|
|
25
|
+
|
|
26
|
+
# Loki
|
|
27
|
+
|
|
28
|
+
**Deterministic guardrails for AI coding agents.**
|
|
29
|
+
|
|
30
|
+
Loki checks every edit your agent makes with real analyzers and precise rules. It
|
|
31
|
+
blocks the dangerous ones before the file changes, tells the agent exactly what
|
|
32
|
+
to fix, and does all of this without calling a model.
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+
|
|
39
|
+
<img src="https://raw.githubusercontent.com/alfredosdpiii/loki/main/docs/demo/demo.gif" alt="Loki blocking an XSS write, a leaked API key and a cross-file type error, then allowing the fix and flagging a complexity hotspot" width="820">
|
|
40
|
+
|
|
41
|
+
<sub>Real hook output from <a href="https://github.com/alfredosdpiii/loki/blob/main/docs/demo/demo.sh">docs/demo/demo.sh</a>. Only the typing is simulated.</sub>
|
|
42
|
+
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
## Why Loki
|
|
46
|
+
|
|
47
|
+
- **It stops problems before they land.** Content rules, Ruff and a full
|
|
48
|
+
TypeScript type check run on the proposed file before the write. XSS, leaked
|
|
49
|
+
keys and broken callers never reach disk.
|
|
50
|
+
- **It only complains about what the edit changed.** Findings are compared
|
|
51
|
+
against the committed file by rule and source line. Existing debt and shifted
|
|
52
|
+
lines pass, so agents aren't blocked by code they didn't touch.
|
|
53
|
+
- **It uses real analyzers.** mypy, `tsc`, golangci-lint, Clippy, Credo and
|
|
54
|
+
Sobelow run on every write, all net-new. Twenty-six tool-free rules cover
|
|
55
|
+
what linters miss: SSRF, open redirects, request-trusted authorization, shell
|
|
56
|
+
`-c` injection, ReDoS, zip slip, prototype pollution, GitHub Actions
|
|
57
|
+
injection and more.
|
|
58
|
+
- **It's fast when it matters.** A per-repository daemon keeps the TypeScript
|
|
59
|
+
checker, `dmypy` and build caches warm. A TypeScript check takes about 40 ms
|
|
60
|
+
warm instead of 500 ms.
|
|
61
|
+
- **It measures structural sloppiness too.** `loki.py slop` scores complexity,
|
|
62
|
+
duplication and import cycles in six languages and flags new hotspots as the
|
|
63
|
+
agent writes them.
|
|
64
|
+
|
|
65
|
+
## How it compares
|
|
66
|
+
|
|
67
|
+
Head to head with [Interlinked CLI](https://github.com/QuentinCody/interlinked-cli)
|
|
68
|
+
(`82307ea`), both installed as Claude Code hooks. Each ran in a fresh sandboxed
|
|
69
|
+
repository per case and repetition. A defect counts only if the right diagnostic
|
|
70
|
+
appears on every repetition.
|
|
71
|
+
|
|
72
|
+
| Suite | Loki caught | Interlinked caught | Loki prevented before write | Loki false blocks | Interlinked false blocks |
|
|
73
|
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
74
|
+
| **Blind holdout** (60 unseen cases, before any tuning) | **33** | 12 | **19** | 3 | 2 |
|
|
75
|
+
| Development corpus | **46/47** | 20/47 | **36** | **0** | 1 |
|
|
76
|
+
| Missing project-local JS tools | **17/17** | 13/17 | **17** | **0** | 1 |
|
|
77
|
+
| Holdout 1 (tuned) | **41/48** | 11/48 | **26** | **0** | 1 |
|
|
78
|
+
| Holdout 2 (tuned) | **42/60** | 12/60 | **29** | **0** | 2 |
|
|
79
|
+
|
|
80
|
+
Median hook latency is on par (402 ms vs 389 ms) with a much shorter tail
|
|
81
|
+
(p95 1.6 s vs 6.4 s). Without project-local JS tools, Loki takes 334 ms against
|
|
82
|
+
Interlinked's 10.8 s. Every holdout defect Interlinked catches, Loki catches too.
|
|
83
|
+
|
|
84
|
+
These are synthetic cases, not production sessions. The blind holdout was written
|
|
85
|
+
by an agent that could not see either product. Read the
|
|
86
|
+
[full results](https://github.com/alfredosdpiii/loki/blob/main/artifacts/comprehensive-summary-2026-09-26.md) and the
|
|
87
|
+
[benchmark protocol](https://github.com/alfredosdpiii/loki/blob/main/benchmarks/README.md).
|
|
88
|
+
|
|
89
|
+
## Quick start
|
|
90
|
+
|
|
91
|
+
Loki needs Python 3.11 or newer and has no runtime dependencies. Install the
|
|
92
|
+
`loki` command, then point it at a Git repository:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
uv tool install loki-guardrails # or: pipx install loki-guardrails
|
|
96
|
+
loki init --dir /path/to/your/repo
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
To try it without installing anything, run `uvx --from loki-guardrails loki init --dir .`.
|
|
100
|
+
You can also clone this repository and run `python3 loki.py init --dir /path/to/repo`.
|
|
101
|
+
|
|
102
|
+
That installs Loki into `.loki/`, registers hooks for every supported agent, and
|
|
103
|
+
adds starter configuration for Ruff, Oxlint, golangci-lint and a GitHub Actions
|
|
104
|
+
check. Existing configuration is merged or left alone.
|
|
105
|
+
|
|
106
|
+
Then, inside the repository:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
loki scan # check the working tree
|
|
110
|
+
loki scan --strict --base origin/main # CI: missing tools fail
|
|
111
|
+
loki slop # structural sloppiness report
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The installed hooks don't use the global `loki` command. `init` copies the
|
|
115
|
+
engine into `.loki/loki.py`, so every repository runs the exact version its
|
|
116
|
+
policy was reviewed against. CI runs the same file, and upgrades happen only
|
|
117
|
+
through `loki init --force` and a reviewed commit. `loki --version` and
|
|
118
|
+
`python3 .loki/loki.py --version` show which version each one is.
|
|
119
|
+
|
|
120
|
+
Codex needs a one-time `/hooks` approval and Pi a trust prompt. The
|
|
121
|
+
[install guide](https://github.com/alfredosdpiii/loki/blob/main/docs/reference.md#install) covers each host.
|
|
122
|
+
|
|
123
|
+
## How it works
|
|
124
|
+
|
|
125
|
+
```mermaid
|
|
126
|
+
flowchart LR
|
|
127
|
+
A[Agent proposes a write] --> B{Pre-write}
|
|
128
|
+
B -->|path, policy, secrets,<br/>security rules, Ruff,<br/>TypeScript types| C[Deny with the exact finding]
|
|
129
|
+
B -->|clean| D[File is written]
|
|
130
|
+
D --> E{Post-write}
|
|
131
|
+
E -->|mypy, golangci-lint, Clippy,<br/>Credo, Sobelow, Oxlint| F[Report net-new findings]
|
|
132
|
+
E --> G[Advisory: new hotspots,<br/>clones, import cycles]
|
|
133
|
+
H[(Warm daemon)] -. keeps analyzers warm .-> B
|
|
134
|
+
H -.-> E
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
1. **Before the write,** Loki reconstructs the file the agent is about to
|
|
138
|
+
produce. It checks the path against protected policy, runs the tool-free
|
|
139
|
+
content rules, and, where supported, runs Ruff and a TypeScript type check on
|
|
140
|
+
the proposed content. A denial carries the precise diagnostic.
|
|
141
|
+
2. **After the write,** the language's analyzers run on what actually landed.
|
|
142
|
+
New findings go back to the agent, while existing debt stays quiet.
|
|
143
|
+
3. **In CI,** `scan` repeats the checks against a base revision, including test
|
|
144
|
+
integrity, dependency policy and lockfile consistency.
|
|
145
|
+
|
|
146
|
+
Loki blocks its own policy files, hook registration and CI workflow from agent
|
|
147
|
+
edits, so an agent can't switch it off.
|
|
148
|
+
|
|
149
|
+
## What it catches
|
|
150
|
+
|
|
151
|
+
| Language | On every write | Tool-free rules |
|
|
152
|
+
| --- | --- | --- |
|
|
153
|
+
| **Python** | Net-new Ruff and mypy (annotated code), import and AST checks | request-trusted authorization, SSRF, path traversal, shell `-c`, timing-unsafe compares, ReDoS, tautological tests |
|
|
154
|
+
| **TypeScript / JS** | Oxlint, project type check (pre-write), floating promises, numeric `.sort()` | XSS sinks, open redirects, `eval`, command and SQL injection, SSRF, prototype pollution, `postMessage` origin, timer leaks, ReDoS, disabled TLS |
|
|
155
|
+
| **Go** | gofmt, go vet, golangci-lint with gosec on changed lines | zip slip |
|
|
156
|
+
| **Rust** | rustfmt, net-new Clippy and compiler errors | placeholders, unchecked `get_unchecked`, unflushed `BufWriter`, shell `-c` |
|
|
157
|
+
| **Elixir / Phoenix** | mix format, net-new Credo and Sobelow | request-trusted authorization, SSRF, open redirects, structural `DateTime` sorts, unhandled `File` results, leaked handles |
|
|
158
|
+
| **Any file** | protected paths, root confinement | hardcoded credentials, merge-conflict markers, GitHub Actions script injection |
|
|
159
|
+
|
|
160
|
+
Missing analyzers are reported as `NOT CHECKED`, never as clean, and
|
|
161
|
+
`LOKI_STRICT=1` turns them into failures. The [reference](https://github.com/alfredosdpiii/loki/blob/main/docs/reference.md)
|
|
162
|
+
documents every rule, threshold and limitation.
|
|
163
|
+
|
|
164
|
+
## Structural sloppiness
|
|
165
|
+
|
|
166
|
+
`loki.py slop` puts a single number on how hard code is to change. It combines
|
|
167
|
+
the erosion metric from
|
|
168
|
+
[Measuring code sloppiness](https://earendil.com/posts/measuring-code-sloppiness/)
|
|
169
|
+
with [trellis](https://github.com/jayminwest/trellis)'s scoring:
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
$ python3 .loki/loki.py slop
|
|
173
|
+
Sloppiness index: 26/100 (lower is better; trellis 0.2.0-provisional weights)
|
|
174
|
+
complexity-erosion 26.2 eroded share 0.94, 1 of 4 functions with CC > 10
|
|
175
|
+
duplication 0.0 density 0.00, 0 clone groups
|
|
176
|
+
import-cycle 0.0 density 0.00, 0 cycles
|
|
177
|
+
hotspot src/discounts.ts:1 discount CC 17, 15 SLOC, mass 65.8
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Complexity is exact for Python, TypeScript/JavaScript, Go and Elixir using each
|
|
181
|
+
language's own parser. It is approximated structurally for Rust, Java, Kotlin, C#,
|
|
182
|
+
C/C++, Swift, Scala, PHP and Ruby. Clones are detected on normalized tokens, so
|
|
183
|
+
renamed copies count. `--base` compares against a revision, and `max_index` or
|
|
184
|
+
`max_index_increase` can gate CI.
|
|
185
|
+
|
|
186
|
+
## Configuration
|
|
187
|
+
|
|
188
|
+
Policy lives in `.loki/loki.json` and is always read from the committed base, so
|
|
189
|
+
an agent can't loosen it mid-session:
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"rule_packs": ["core", "python", "typescript", "phoenix", "shell"],
|
|
194
|
+
"shell_commands": [
|
|
195
|
+
{"command": "npm test", "cwd": ".", "inputs": ["package.json", "package-lock.json"]}
|
|
196
|
+
],
|
|
197
|
+
"slop": {"max_index": 40, "max_index_increase": 2, "block": false},
|
|
198
|
+
"elixir_security": {"sobelow": {"block": "high", "warn": "medium"}}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
| Setting | Default | Effect |
|
|
203
|
+
| --- | --- | --- |
|
|
204
|
+
| `typescript_check` | on when `tsconfig.json` exists | `false` disables it; `true` makes setup problems block |
|
|
205
|
+
| `slop.block` | `false` | Turns new hotspots, clones and cycles from advice into failures |
|
|
206
|
+
| `shell_commands` | none | Exact, reviewed shell commands the shell guard admits |
|
|
207
|
+
| `LOKI_STRICT=1` | off | Missing analyzers fail instead of reporting `NOT CHECKED` |
|
|
208
|
+
| `LOKI_DAEMON=0` | on | Runs every hook in-process |
|
|
209
|
+
|
|
210
|
+
## Supported agents
|
|
211
|
+
|
|
212
|
+
| Agent | Integration |
|
|
213
|
+
| --- | --- |
|
|
214
|
+
| Claude Code | `.claude/settings.json` hooks |
|
|
215
|
+
| Codex | `.codex/hooks.json` hooks |
|
|
216
|
+
| Factory Droid | `.factory/hooks.json` hooks |
|
|
217
|
+
| Pi | `.pi/extensions/loki.ts` |
|
|
218
|
+
| OMP | `.omp/extensions/loki.ts` |
|
|
219
|
+
|
|
220
|
+
## Documentation
|
|
221
|
+
|
|
222
|
+
- [Reference](https://github.com/alfredosdpiii/loki/blob/main/docs/reference.md): every check, rule, threshold and limitation
|
|
223
|
+
- [Benchmark protocol](https://github.com/alfredosdpiii/loki/blob/main/benchmarks/README.md) and the
|
|
224
|
+
[latest results](https://github.com/alfredosdpiii/loki/blob/main/artifacts/comprehensive-summary-2026-09-26.md)
|
|
225
|
+
- [Blind holdout cases](https://github.com/alfredosdpiii/loki/blob/main/benchmarks/holdout2_cases.json) and the
|
|
226
|
+
[runner](https://github.com/alfredosdpiii/loki/blob/main/benchmarks/holdout.py)
|
|
227
|
+
|
|
228
|
+
## Development
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
uv run --frozen pytest -q
|
|
232
|
+
bun test ./tests/loki-shim.test.ts ./tests/loki-omp.test.ts
|
|
233
|
+
ruff check --config templates/.ruff.toml loki.py tests benchmarks
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Regenerate the demo with `asciinema rec -c "bash docs/demo/demo.sh" docs/demo/demo.cast`
|
|
237
|
+
followed by `agg docs/demo/demo.cast docs/demo/demo.gif`.
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# Loki
|
|
4
|
+
|
|
5
|
+
**Deterministic guardrails for AI coding agents.**
|
|
6
|
+
|
|
7
|
+
Loki checks every edit your agent makes with real analyzers and precise rules. It
|
|
8
|
+
blocks the dangerous ones before the file changes, tells the agent exactly what
|
|
9
|
+
to fix, and does all of this without calling a model.
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
<img src="https://raw.githubusercontent.com/alfredosdpiii/loki/main/docs/demo/demo.gif" alt="Loki blocking an XSS write, a leaked API key and a cross-file type error, then allowing the fix and flagging a complexity hotspot" width="820">
|
|
17
|
+
|
|
18
|
+
<sub>Real hook output from <a href="https://github.com/alfredosdpiii/loki/blob/main/docs/demo/demo.sh">docs/demo/demo.sh</a>. Only the typing is simulated.</sub>
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
## Why Loki
|
|
23
|
+
|
|
24
|
+
- **It stops problems before they land.** Content rules, Ruff and a full
|
|
25
|
+
TypeScript type check run on the proposed file before the write. XSS, leaked
|
|
26
|
+
keys and broken callers never reach disk.
|
|
27
|
+
- **It only complains about what the edit changed.** Findings are compared
|
|
28
|
+
against the committed file by rule and source line. Existing debt and shifted
|
|
29
|
+
lines pass, so agents aren't blocked by code they didn't touch.
|
|
30
|
+
- **It uses real analyzers.** mypy, `tsc`, golangci-lint, Clippy, Credo and
|
|
31
|
+
Sobelow run on every write, all net-new. Twenty-six tool-free rules cover
|
|
32
|
+
what linters miss: SSRF, open redirects, request-trusted authorization, shell
|
|
33
|
+
`-c` injection, ReDoS, zip slip, prototype pollution, GitHub Actions
|
|
34
|
+
injection and more.
|
|
35
|
+
- **It's fast when it matters.** A per-repository daemon keeps the TypeScript
|
|
36
|
+
checker, `dmypy` and build caches warm. A TypeScript check takes about 40 ms
|
|
37
|
+
warm instead of 500 ms.
|
|
38
|
+
- **It measures structural sloppiness too.** `loki.py slop` scores complexity,
|
|
39
|
+
duplication and import cycles in six languages and flags new hotspots as the
|
|
40
|
+
agent writes them.
|
|
41
|
+
|
|
42
|
+
## How it compares
|
|
43
|
+
|
|
44
|
+
Head to head with [Interlinked CLI](https://github.com/QuentinCody/interlinked-cli)
|
|
45
|
+
(`82307ea`), both installed as Claude Code hooks. Each ran in a fresh sandboxed
|
|
46
|
+
repository per case and repetition. A defect counts only if the right diagnostic
|
|
47
|
+
appears on every repetition.
|
|
48
|
+
|
|
49
|
+
| Suite | Loki caught | Interlinked caught | Loki prevented before write | Loki false blocks | Interlinked false blocks |
|
|
50
|
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
51
|
+
| **Blind holdout** (60 unseen cases, before any tuning) | **33** | 12 | **19** | 3 | 2 |
|
|
52
|
+
| Development corpus | **46/47** | 20/47 | **36** | **0** | 1 |
|
|
53
|
+
| Missing project-local JS tools | **17/17** | 13/17 | **17** | **0** | 1 |
|
|
54
|
+
| Holdout 1 (tuned) | **41/48** | 11/48 | **26** | **0** | 1 |
|
|
55
|
+
| Holdout 2 (tuned) | **42/60** | 12/60 | **29** | **0** | 2 |
|
|
56
|
+
|
|
57
|
+
Median hook latency is on par (402 ms vs 389 ms) with a much shorter tail
|
|
58
|
+
(p95 1.6 s vs 6.4 s). Without project-local JS tools, Loki takes 334 ms against
|
|
59
|
+
Interlinked's 10.8 s. Every holdout defect Interlinked catches, Loki catches too.
|
|
60
|
+
|
|
61
|
+
These are synthetic cases, not production sessions. The blind holdout was written
|
|
62
|
+
by an agent that could not see either product. Read the
|
|
63
|
+
[full results](https://github.com/alfredosdpiii/loki/blob/main/artifacts/comprehensive-summary-2026-09-26.md) and the
|
|
64
|
+
[benchmark protocol](https://github.com/alfredosdpiii/loki/blob/main/benchmarks/README.md).
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
Loki needs Python 3.11 or newer and has no runtime dependencies. Install the
|
|
69
|
+
`loki` command, then point it at a Git repository:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
uv tool install loki-guardrails # or: pipx install loki-guardrails
|
|
73
|
+
loki init --dir /path/to/your/repo
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
To try it without installing anything, run `uvx --from loki-guardrails loki init --dir .`.
|
|
77
|
+
You can also clone this repository and run `python3 loki.py init --dir /path/to/repo`.
|
|
78
|
+
|
|
79
|
+
That installs Loki into `.loki/`, registers hooks for every supported agent, and
|
|
80
|
+
adds starter configuration for Ruff, Oxlint, golangci-lint and a GitHub Actions
|
|
81
|
+
check. Existing configuration is merged or left alone.
|
|
82
|
+
|
|
83
|
+
Then, inside the repository:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
loki scan # check the working tree
|
|
87
|
+
loki scan --strict --base origin/main # CI: missing tools fail
|
|
88
|
+
loki slop # structural sloppiness report
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The installed hooks don't use the global `loki` command. `init` copies the
|
|
92
|
+
engine into `.loki/loki.py`, so every repository runs the exact version its
|
|
93
|
+
policy was reviewed against. CI runs the same file, and upgrades happen only
|
|
94
|
+
through `loki init --force` and a reviewed commit. `loki --version` and
|
|
95
|
+
`python3 .loki/loki.py --version` show which version each one is.
|
|
96
|
+
|
|
97
|
+
Codex needs a one-time `/hooks` approval and Pi a trust prompt. The
|
|
98
|
+
[install guide](https://github.com/alfredosdpiii/loki/blob/main/docs/reference.md#install) covers each host.
|
|
99
|
+
|
|
100
|
+
## How it works
|
|
101
|
+
|
|
102
|
+
```mermaid
|
|
103
|
+
flowchart LR
|
|
104
|
+
A[Agent proposes a write] --> B{Pre-write}
|
|
105
|
+
B -->|path, policy, secrets,<br/>security rules, Ruff,<br/>TypeScript types| C[Deny with the exact finding]
|
|
106
|
+
B -->|clean| D[File is written]
|
|
107
|
+
D --> E{Post-write}
|
|
108
|
+
E -->|mypy, golangci-lint, Clippy,<br/>Credo, Sobelow, Oxlint| F[Report net-new findings]
|
|
109
|
+
E --> G[Advisory: new hotspots,<br/>clones, import cycles]
|
|
110
|
+
H[(Warm daemon)] -. keeps analyzers warm .-> B
|
|
111
|
+
H -.-> E
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
1. **Before the write,** Loki reconstructs the file the agent is about to
|
|
115
|
+
produce. It checks the path against protected policy, runs the tool-free
|
|
116
|
+
content rules, and, where supported, runs Ruff and a TypeScript type check on
|
|
117
|
+
the proposed content. A denial carries the precise diagnostic.
|
|
118
|
+
2. **After the write,** the language's analyzers run on what actually landed.
|
|
119
|
+
New findings go back to the agent, while existing debt stays quiet.
|
|
120
|
+
3. **In CI,** `scan` repeats the checks against a base revision, including test
|
|
121
|
+
integrity, dependency policy and lockfile consistency.
|
|
122
|
+
|
|
123
|
+
Loki blocks its own policy files, hook registration and CI workflow from agent
|
|
124
|
+
edits, so an agent can't switch it off.
|
|
125
|
+
|
|
126
|
+
## What it catches
|
|
127
|
+
|
|
128
|
+
| Language | On every write | Tool-free rules |
|
|
129
|
+
| --- | --- | --- |
|
|
130
|
+
| **Python** | Net-new Ruff and mypy (annotated code), import and AST checks | request-trusted authorization, SSRF, path traversal, shell `-c`, timing-unsafe compares, ReDoS, tautological tests |
|
|
131
|
+
| **TypeScript / JS** | Oxlint, project type check (pre-write), floating promises, numeric `.sort()` | XSS sinks, open redirects, `eval`, command and SQL injection, SSRF, prototype pollution, `postMessage` origin, timer leaks, ReDoS, disabled TLS |
|
|
132
|
+
| **Go** | gofmt, go vet, golangci-lint with gosec on changed lines | zip slip |
|
|
133
|
+
| **Rust** | rustfmt, net-new Clippy and compiler errors | placeholders, unchecked `get_unchecked`, unflushed `BufWriter`, shell `-c` |
|
|
134
|
+
| **Elixir / Phoenix** | mix format, net-new Credo and Sobelow | request-trusted authorization, SSRF, open redirects, structural `DateTime` sorts, unhandled `File` results, leaked handles |
|
|
135
|
+
| **Any file** | protected paths, root confinement | hardcoded credentials, merge-conflict markers, GitHub Actions script injection |
|
|
136
|
+
|
|
137
|
+
Missing analyzers are reported as `NOT CHECKED`, never as clean, and
|
|
138
|
+
`LOKI_STRICT=1` turns them into failures. The [reference](https://github.com/alfredosdpiii/loki/blob/main/docs/reference.md)
|
|
139
|
+
documents every rule, threshold and limitation.
|
|
140
|
+
|
|
141
|
+
## Structural sloppiness
|
|
142
|
+
|
|
143
|
+
`loki.py slop` puts a single number on how hard code is to change. It combines
|
|
144
|
+
the erosion metric from
|
|
145
|
+
[Measuring code sloppiness](https://earendil.com/posts/measuring-code-sloppiness/)
|
|
146
|
+
with [trellis](https://github.com/jayminwest/trellis)'s scoring:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
$ python3 .loki/loki.py slop
|
|
150
|
+
Sloppiness index: 26/100 (lower is better; trellis 0.2.0-provisional weights)
|
|
151
|
+
complexity-erosion 26.2 eroded share 0.94, 1 of 4 functions with CC > 10
|
|
152
|
+
duplication 0.0 density 0.00, 0 clone groups
|
|
153
|
+
import-cycle 0.0 density 0.00, 0 cycles
|
|
154
|
+
hotspot src/discounts.ts:1 discount CC 17, 15 SLOC, mass 65.8
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Complexity is exact for Python, TypeScript/JavaScript, Go and Elixir using each
|
|
158
|
+
language's own parser. It is approximated structurally for Rust, Java, Kotlin, C#,
|
|
159
|
+
C/C++, Swift, Scala, PHP and Ruby. Clones are detected on normalized tokens, so
|
|
160
|
+
renamed copies count. `--base` compares against a revision, and `max_index` or
|
|
161
|
+
`max_index_increase` can gate CI.
|
|
162
|
+
|
|
163
|
+
## Configuration
|
|
164
|
+
|
|
165
|
+
Policy lives in `.loki/loki.json` and is always read from the committed base, so
|
|
166
|
+
an agent can't loosen it mid-session:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"rule_packs": ["core", "python", "typescript", "phoenix", "shell"],
|
|
171
|
+
"shell_commands": [
|
|
172
|
+
{"command": "npm test", "cwd": ".", "inputs": ["package.json", "package-lock.json"]}
|
|
173
|
+
],
|
|
174
|
+
"slop": {"max_index": 40, "max_index_increase": 2, "block": false},
|
|
175
|
+
"elixir_security": {"sobelow": {"block": "high", "warn": "medium"}}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
| Setting | Default | Effect |
|
|
180
|
+
| --- | --- | --- |
|
|
181
|
+
| `typescript_check` | on when `tsconfig.json` exists | `false` disables it; `true` makes setup problems block |
|
|
182
|
+
| `slop.block` | `false` | Turns new hotspots, clones and cycles from advice into failures |
|
|
183
|
+
| `shell_commands` | none | Exact, reviewed shell commands the shell guard admits |
|
|
184
|
+
| `LOKI_STRICT=1` | off | Missing analyzers fail instead of reporting `NOT CHECKED` |
|
|
185
|
+
| `LOKI_DAEMON=0` | on | Runs every hook in-process |
|
|
186
|
+
|
|
187
|
+
## Supported agents
|
|
188
|
+
|
|
189
|
+
| Agent | Integration |
|
|
190
|
+
| --- | --- |
|
|
191
|
+
| Claude Code | `.claude/settings.json` hooks |
|
|
192
|
+
| Codex | `.codex/hooks.json` hooks |
|
|
193
|
+
| Factory Droid | `.factory/hooks.json` hooks |
|
|
194
|
+
| Pi | `.pi/extensions/loki.ts` |
|
|
195
|
+
| OMP | `.omp/extensions/loki.ts` |
|
|
196
|
+
|
|
197
|
+
## Documentation
|
|
198
|
+
|
|
199
|
+
- [Reference](https://github.com/alfredosdpiii/loki/blob/main/docs/reference.md): every check, rule, threshold and limitation
|
|
200
|
+
- [Benchmark protocol](https://github.com/alfredosdpiii/loki/blob/main/benchmarks/README.md) and the
|
|
201
|
+
[latest results](https://github.com/alfredosdpiii/loki/blob/main/artifacts/comprehensive-summary-2026-09-26.md)
|
|
202
|
+
- [Blind holdout cases](https://github.com/alfredosdpiii/loki/blob/main/benchmarks/holdout2_cases.json) and the
|
|
203
|
+
[runner](https://github.com/alfredosdpiii/loki/blob/main/benchmarks/holdout.py)
|
|
204
|
+
|
|
205
|
+
## Development
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
uv run --frozen pytest -q
|
|
209
|
+
bun test ./tests/loki-shim.test.ts ./tests/loki-omp.test.ts
|
|
210
|
+
ruff check --config templates/.ruff.toml loki.py tests benchmarks
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Regenerate the demo with `asciinema rec -c "bash docs/demo/demo.sh" docs/demo/demo.cast`
|
|
214
|
+
followed by `agg docs/demo/demo.cast docs/demo/demo.gif`.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Benchmark protocol
|
|
2
|
+
|
|
3
|
+
The earlier pre-write comparison does not establish an overall winner. It leaves
|
|
4
|
+
out checks that run after edits, whole-project analysis, and ordinary repair work.
|
|
5
|
+
|
|
6
|
+
`comprehensive.py` invokes the installed Claude command hooks for both products.
|
|
7
|
+
It writes an admitted source edit into a disposable repository, then invokes the
|
|
8
|
+
installed post-write handlers. It never executes proposed shell commands or
|
|
9
|
+
application code. Explicit audit commands may compile the controlled fixtures.
|
|
10
|
+
|
|
11
|
+
## Cases and scoring
|
|
12
|
+
|
|
13
|
+
`corpus.py` contains paired defects and controls, exact replacements, cross-file
|
|
14
|
+
contract changes, existing-debt shifts, break/repair sequences, protected-path
|
|
15
|
+
attempts, and 10/1,000/10,000-file workloads. Languages are Python, TypeScript,
|
|
16
|
+
JavaScript, Go, Rust, and Elixir/Phoenix.
|
|
17
|
+
|
|
18
|
+
The corpus deliberately includes semantic security cases that neither product may
|
|
19
|
+
recognize. SSRF and request-controlled authorization stay in the denominator.
|
|
20
|
+
Cases reflect the author's knowledge of both products. They are synthetic, not an
|
|
21
|
+
independent holdout or a representative sample of production changes.
|
|
22
|
+
|
|
23
|
+
Before running, the runner saves the complete case list, its hash, the randomized
|
|
24
|
+
schedule, tool versions, command line, and source hashes. Each result uses an
|
|
25
|
+
exclusive file creation. Existing evidence cannot be replaced by another run.
|
|
26
|
+
Source identity is checked again when the run finishes.
|
|
27
|
+
|
|
28
|
+
The scorecard distinguishes:
|
|
29
|
+
|
|
30
|
+
- **Prevention:** a pre-hook denies the operation and emits a matching diagnostic.
|
|
31
|
+
- **Post-write detection:** a matching diagnostic reaches the host after source
|
|
32
|
+
bytes land. This is not prevention, rollback, or an OS security boundary.
|
|
33
|
+
- **Unrelated blocking:** denial without evidence of the intended defect.
|
|
34
|
+
- **False blocking:** a control is blocked in any repetition, before or after writing.
|
|
35
|
+
- **Unavailable checks:** reported separately, even if the overall hook admits the edit.
|
|
36
|
+
- **Infrastructure failure:** remains in the denominator and earns no detection credit.
|
|
37
|
+
|
|
38
|
+
An accuracy result needs the same successful detection on every repetition.
|
|
39
|
+
Three repetitions are three timing/stability samples, not three independent cases.
|
|
40
|
+
Exit-zero native JSON denials count as denials. Exit-zero stderr alone does not
|
|
41
|
+
count as feedback delivered to Claude. Audit scoring examines actual diagnostic
|
|
42
|
+
entries, not the names of checks that reported zero findings.
|
|
43
|
+
|
|
44
|
+
The scorecard also decodes JSON feedback before matching individual diagnostic
|
|
45
|
+
lines. Otherwise a regex can span escaped `\n` sequences and mistake unrelated
|
|
46
|
+
advice for a compiler finding. Node module-format notices do not count as syntax
|
|
47
|
+
detection. Raw records retain provisional outcomes; the scorecard lists every
|
|
48
|
+
correction and hashes the final scorer.
|
|
49
|
+
|
|
50
|
+
Control feedback includes missing-tool notices and advisory messages. It is not
|
|
51
|
+
automatically a false positive. The report preserves the raw output for review.
|
|
52
|
+
Cold and startup-warmed timings are separate. Each repetition gets a fresh
|
|
53
|
+
repository, home, and daemon, avoiding leaked reservations and diagnostic caches.
|
|
54
|
+
The first trial has no warmup. Later trials send two git-status pre-hook envelopes
|
|
55
|
+
before the case, without executing the commands. That warms startup, not compiler
|
|
56
|
+
result caches. "Cold" does not mean flushed OS caches. Latency includes process
|
|
57
|
+
and sandbox startup.
|
|
58
|
+
|
|
59
|
+
## Isolation and tool parity
|
|
60
|
+
|
|
61
|
+
Each product/case/profile gets a new repository and home. Bubblewrap denies
|
|
62
|
+
network access, mounts the host filesystem read-only, and allows writes only to
|
|
63
|
+
the fixture tree and private temporary storage. There is no unsandboxed fallback.
|
|
64
|
+
The runner starts only known local binaries and uses an environment allowlist.
|
|
65
|
+
It uses the user's existing Git identity for fixture commits.
|
|
66
|
+
|
|
67
|
+
Repositories live under the ignored `artifacts/tmp/b/` directory by default,
|
|
68
|
+
outside OS temporary roots. Interlinked applies a distinct scratchpad policy to
|
|
69
|
+
paths under `/tmp`; measuring that policy would not represent ordinary repository
|
|
70
|
+
edits. `--work-dir` overrides the fixture parent. Keep its path short enough for
|
|
71
|
+
Unix domain sockets.
|
|
72
|
+
|
|
73
|
+
Both products receive the same analyzer paths. The shared profile supplies
|
|
74
|
+
TypeScript, Oxlint, Biome with its recommended lint config, Ruff, mypy,
|
|
75
|
+
golangci-lint, Go, Rust, and prepared Phoenix dependencies. This does not mean
|
|
76
|
+
both products invoke every available analyzer.
|
|
77
|
+
|
|
78
|
+
Loki's shell guard and a committed exact `npm test` permission are enabled.
|
|
79
|
+
Interlinked uses its balanced project installation. Other Loki settings remain
|
|
80
|
+
at their shipped values, including its disabled-by-default project type checker.
|
|
81
|
+
`configured.py` repeats the TypeScript cases with `"typescript_check": true`.
|
|
82
|
+
Keep that result separate from the ordinary installation.
|
|
83
|
+
|
|
84
|
+
The `missing-js` profile omits project-local JS analyzer links. It does not remove
|
|
85
|
+
system-wide tools or the competitor's own packaged dependencies. It measures that
|
|
86
|
+
specific degradation, not a completely tool-free machine.
|
|
87
|
+
|
|
88
|
+
Go/Rust audit results use `loki scan --base HEAD` and `interlinked verify --json`.
|
|
89
|
+
These have different product-defined scopes. Their findings are never added to
|
|
90
|
+
the ordinary-hook detection total.
|
|
91
|
+
|
|
92
|
+
The shared-scaffolding matrix places a JS package manifest in every fixture to
|
|
93
|
+
support its shell-grant controls. That can affect project discovery in non-JS
|
|
94
|
+
repositories. `native_projects.py` is a separate sensitivity run: Python gets
|
|
95
|
+
`pyproject.toml` with Ruff and mypy sections, and Go/Rust/Phoenix retain only their
|
|
96
|
+
native manifests. It omits the irrelevant npm grant for those fixtures. Do not
|
|
97
|
+
pool its observations with the shared-scaffolding results.
|
|
98
|
+
|
|
99
|
+
## Reproduce
|
|
100
|
+
|
|
101
|
+
Prepare the toolchains first, outside the network-isolated run. The competitor
|
|
102
|
+
checkout must be clean at `207330d8131c5203ecc74e9fd4c24ba416463718`, with its
|
|
103
|
+
`dist/` build present. The Phoenix project must use
|
|
104
|
+
`fixtures/phoenix/mix.exs` and `mix.lock`, with dependencies compiled under
|
|
105
|
+
Elixir 1.17.3 and a compatible OTP 27 installation. Provide a compatible Hex
|
|
106
|
+
archive as well. No global toolchain setting needs to change.
|
|
107
|
+
|
|
108
|
+
Run from the Loki checkout, substituting absolute paths:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
ERL_FLAGS='+S 4:4' /usr/bin/python3 benchmarks/comprehensive.py \
|
|
112
|
+
--interlinked /path/to/interlinked \
|
|
113
|
+
--node /path/to/node-23/bin/node \
|
|
114
|
+
--oxlint /path/to/oxlint-tools/node_modules/.bin/oxlint \
|
|
115
|
+
--typescript /path/to/typescript-tools/node_modules/typescript \
|
|
116
|
+
--biome /path/to/biome-tools/node_modules/.bin/biome \
|
|
117
|
+
--python-tools /path/to/mypy-venv/bin \
|
|
118
|
+
--golangci /path/to/golangci-lint \
|
|
119
|
+
--phoenix /path/to/prepared-phoenix \
|
|
120
|
+
--hex-archive /path/to/hex-archive \
|
|
121
|
+
--erlang-bin /path/to/otp-27/bin \
|
|
122
|
+
--runs 3 --seed 20260921 --profiles shared missing-js --scan \
|
|
123
|
+
--output /path/to/new-evidence-directory
|
|
124
|
+
|
|
125
|
+
python3 -m benchmarks.report_comprehensive /path/to/new-evidence-directory
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Use an actual Python executable, rather than a toolchain shim that might rewrite
|
|
129
|
+
`PATH` during startup. The explicit `--erlang-bin` also prevents that environment
|
|
130
|
+
problem inside fixtures.
|
|
131
|
+
|
|
132
|
+
For the type-check-enabled run, replace `comprehensive.py` with `configured.py`,
|
|
133
|
+
use `--profiles shared --case typescript`, and choose a new output directory.
|
|
134
|
+
That entry point changes only accepted fixture policy, not either product's code.
|
|
135
|
+
Its own hash is included in the evidence identity.
|
|
136
|
+
|
|
137
|
+
For native project discovery, use `native_projects.py --profiles shared` and
|
|
138
|
+
`--case '(^python/|^go/|^rust/|^elixir/|/python/)'`, with the same tool arguments
|
|
139
|
+
and a new output directory. This tests configuration sensitivity without changing
|
|
140
|
+
either product or the defect/control source.
|
|
141
|
+
|
|
142
|
+
## Separate integration and regression suites
|
|
143
|
+
|
|
144
|
+
- `host_context.py`: real installed hosts with fresh homes and a loopback model
|
|
145
|
+
stub, with hooks enabled and disabled. This proves startup discovery/context
|
|
146
|
+
delivery, not live-model tool enforcement.
|
|
147
|
+
- `phoenix.py`: installed ordinary hooks plus project-tier compilation and HEEx
|
|
148
|
+
checks under multiple Sobelow confidence thresholds.
|
|
149
|
+
- `language_rules.py`: targeted analyzer defect/repair regressions. These were
|
|
150
|
+
developed with Loki's policies and are not independent comparison cases.
|
|
151
|
+
- `tests/loki-shim.test.ts` and `tests/loki-omp.test.ts`: actual checker subprocesses
|
|
152
|
+
through adapter callbacks, not running host inference sessions.
|
|
153
|
+
|
|
154
|
+
The smoke-run directories preserve setup failures. They are not merged into the
|
|
155
|
+
final comparison. Do not silently discard failures from a completed final run or
|
|
156
|
+
change cases and then reuse its manifest.
|
|
157
|
+
|
|
158
|
+
This protocol still does not measure long-running autonomous sessions, production
|
|
159
|
+
incident prevention, online dependency checks, all supported host write formats,
|
|
160
|
+
or unknown attacks. Those require separate experiments and explicit authorization
|
|
161
|
+
before using private repositories or paid model endpoints.
|