loki-mode 8.5.2 → 8.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +225 -6
- package/autonomy/run.sh +106 -9
- package/autonomy/telemetry.sh +45 -0
- package/autonomy/verify.sh +85 -19
- package/completions/_loki +1 -0
- package/completions/loki.bash +1 -1
- package/dashboard/__init__.py +1 -1
- package/docs/EVALUATING.md +28 -0
- package/docs/PRIVACY.md +25 -2
- package/docs/air-gapped.md +91 -0
- package/docs/brownfield.md +120 -0
- package/docs/cost-controls.md +88 -0
- package/docs/environment-variables.md +102 -0
- package/docs/exit-codes.md +130 -0
- package/docs/image-provenance.md +124 -0
- package/loki-ts/dist/loki.js +288 -284
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Environment variables
|
|
2
|
+
|
|
3
|
+
The operator-facing knobs, with defaults read from the source rather than from
|
|
4
|
+
memory. Every variable on this page is asserted by a test to still exist, so
|
|
5
|
+
this document cannot quietly rot into fiction.
|
|
6
|
+
|
|
7
|
+
## What this page is not
|
|
8
|
+
|
|
9
|
+
The codebase references a few hundred `LOKI_*` tokens. Most are internal
|
|
10
|
+
plumbing between the CLI and the runner (`LOKI_REG_TARGET`,
|
|
11
|
+
`LOKI_CI_JSON_FINDINGS`, and similar), or prefix fragments that are never a
|
|
12
|
+
whole variable. Publishing that number as an "operator surface" would be
|
|
13
|
+
misleading, so this page covers only what an operator would deliberately set.
|
|
14
|
+
|
|
15
|
+
`loki config schema` lists 64 more keys that map to environment variables and
|
|
16
|
+
can be written to `.loki/config.yaml`. Those are not repeated here. The
|
|
17
|
+
variables below are the ones **not** in that schema -- historically the ones
|
|
18
|
+
with nowhere to look them up.
|
|
19
|
+
|
|
20
|
+
## Running a build
|
|
21
|
+
|
|
22
|
+
| Variable | Default | Effect |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| `LOKI_PRD_FILE` | none | Path to a spec file, as an alternative to the positional argument. |
|
|
25
|
+
| `LOKI_MAX_ITERATIONS` | `1000` | Hard cap on iterations. Reaching it is a deterministic terminal failure, not a success. Also in `config schema`. |
|
|
26
|
+
| `LOKI_BUDGET_LIMIT` | unset (no cap) | Spend cap in USD. On exhaustion the run stops and reports a terminal failure -- see [exit codes](./exit-codes.md). |
|
|
27
|
+
| `LOKI_MAX_DURATION` | unset (no cap) | Wall-clock cap in seconds. Stops cleanly at the next iteration boundary with a `max_duration_reached` terminal status. `loki start --max-duration` also accepts `90m` / `2h`. |
|
|
28
|
+
| `LOKI_AUTO_CONFIRM` | unset | `true`/`false` to control prompts. Takes precedence over `CI`. |
|
|
29
|
+
| `LOKI_CONFIG_DUMP` | `0` | `1` prints the resolved configuration and exits **without starting a run or spending anything**. |
|
|
30
|
+
|
|
31
|
+
For a cost estimate before committing to a run, `loki plan <spec> --json` is
|
|
32
|
+
the better tool: it reports complexity, iterations, tokens and cost without
|
|
33
|
+
executing. See [cost controls](./cost-controls.md) for how the three caps
|
|
34
|
+
interact and why hitting one is a failure rather than a success.
|
|
35
|
+
|
|
36
|
+
## Choosing a model and provider
|
|
37
|
+
|
|
38
|
+
| Variable | Default | Effect |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `LOKI_PROVIDER` | `claude` | `claude`, `cline`, `codex`, or `aider`. |
|
|
41
|
+
| `LOKI_MAX_TIER` | unlimited | Caps model tier, so a run cannot escalate past what you are willing to pay for. |
|
|
42
|
+
| `LOKI_TIER` | per-phase default | Forces a specific tier for the run. |
|
|
43
|
+
| `LOKI_SESSION_MODEL` | provider default | Pins the session model explicitly. |
|
|
44
|
+
| `LOKI_MODEL_OVERRIDE` | unset | Overrides the resolved model outright. |
|
|
45
|
+
|
|
46
|
+
`LOKI_MAX_TIER` is the cost control worth knowing: it bounds escalation, while
|
|
47
|
+
`LOKI_BUDGET_LIMIT` bounds total spend. They answer different questions and are
|
|
48
|
+
usefully set together.
|
|
49
|
+
|
|
50
|
+
## Output volume
|
|
51
|
+
|
|
52
|
+
| Variable | Default | Effect |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `LOKI_LOG_LEVEL` | `info` | `debug`, `info`, `warn`, or `error`. |
|
|
55
|
+
| `LOKI_QUIET` | `0` | `1` is shorthand for `warn`. |
|
|
56
|
+
|
|
57
|
+
**Errors are never suppressed.** `error` is the floor, so even the quietest
|
|
58
|
+
setting still prints failures -- a verbosity control that could hide why a
|
|
59
|
+
build failed would be a footgun. An unrecognized value falls back to `info`
|
|
60
|
+
rather than silencing the run, so a typo in a pipeline config cannot blind you.
|
|
61
|
+
|
|
62
|
+
Available as flags too: `loki start --quiet`, `loki start --log-level LEVEL`.
|
|
63
|
+
|
|
64
|
+
Decorative output (the HUD, the completion card, the start headline) already
|
|
65
|
+
suppresses itself when stdout is not a TTY, so CI logs were never the wall of
|
|
66
|
+
banners you might expect. These variables control the remaining `[INFO]` and
|
|
67
|
+
`[STEP]` lines.
|
|
68
|
+
|
|
69
|
+
## Platform integration
|
|
70
|
+
|
|
71
|
+
| Variable | Default | Effect |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `LOKI_DURABLE_STATE` | `0` | `1` enables durable state **and** the richer process-exit contract that lets Kubernetes distinguish a deterministic failure from a crash. See [exit codes](./exit-codes.md). |
|
|
74
|
+
| `LOKI_SDK_LOOP` | unset | Routes the run through the Bun/TypeScript runner instead of bash. Both implement the same exit contract. |
|
|
75
|
+
|
|
76
|
+
`LOKI_DURABLE_STATE=1` is the one to set in a Job or task definition. Without
|
|
77
|
+
it every failure collapses to exit 1 and the platform cannot tell "re-running
|
|
78
|
+
this is pointless" from "this crashed and should resume".
|
|
79
|
+
|
|
80
|
+
## Precedence
|
|
81
|
+
|
|
82
|
+
Command-line flags beat environment variables, which beat `.loki/config.yaml`,
|
|
83
|
+
which beats `~/.config/loki-mode/config.yaml`.
|
|
84
|
+
|
|
85
|
+
To see what actually resolved, without starting a run:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
LOKI_CONFIG_DUMP=1 loki start ./prd.md
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Setting these persistently
|
|
92
|
+
|
|
93
|
+
`loki config set` writes to the config file for the keys it supports:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
loki config set budget 25
|
|
97
|
+
loki config set provider claude
|
|
98
|
+
loki config set maxTier sonnet
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`loki config schema` lists every key the config file understands, and
|
|
102
|
+
`loki config show` prints the current effective values.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Exit codes
|
|
2
|
+
|
|
3
|
+
Every code below was read from the source, not from a help text. If a command
|
|
4
|
+
is absent from this page it returns only the shell defaults (0 on success,
|
|
5
|
+
nonzero on failure) and you should not build a gate on anything finer.
|
|
6
|
+
|
|
7
|
+
## The one rule
|
|
8
|
+
|
|
9
|
+
**Severity rises with the code.** `[ $rc -ge 2 ]` always means "worse than the
|
|
10
|
+
level-1 outcome" for any command on this page. If you remember nothing else,
|
|
11
|
+
remember that a bigger number is never better news.
|
|
12
|
+
|
|
13
|
+
## `loki start`
|
|
14
|
+
|
|
15
|
+
Two contracts, and which one you get depends on an environment variable. This
|
|
16
|
+
is the part most likely to surprise a script author.
|
|
17
|
+
|
|
18
|
+
### Default (local, CI)
|
|
19
|
+
|
|
20
|
+
| Code | Meaning |
|
|
21
|
+
|---|---|
|
|
22
|
+
| 0 | The run completed |
|
|
23
|
+
| nonzero | Something went wrong |
|
|
24
|
+
|
|
25
|
+
There is no finer signal. A gate that needs to tell "failed the quality gate"
|
|
26
|
+
from "crashed" must opt into the durable contract below.
|
|
27
|
+
|
|
28
|
+
### With `LOKI_DURABLE_STATE=1` (the platform contract)
|
|
29
|
+
|
|
30
|
+
Written for a Kubernetes Job, an ECS task, or a systemd unit that has to decide
|
|
31
|
+
whether retrying is worth anything. The distinction it draws is **will running
|
|
32
|
+
this again produce a different result**.
|
|
33
|
+
|
|
34
|
+
| Code | Meaning | Should the platform retry? |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| 0 | Completed, or a human stopped it (council approved, completion promise, force-stop, paused, interrupted, stopped) | No. It is done, or a person is driving. |
|
|
37
|
+
| 20 | Deterministic terminal failure (failed a gate, max iterations, max retries, **budget exceeded**, **wall-clock cap reached**, policy blocked, contradictory spec) | **No.** The same inputs fail the same way; a retry only spends money to arrive here again. |
|
|
38
|
+
| any other nonzero | Crash (SIGKILL, eviction, node loss) | Yes. The restarted run resumes from the durable volume. |
|
|
39
|
+
|
|
40
|
+
`budget_exceeded` sits with the failures deliberately. It used to exit 0 on the
|
|
41
|
+
reasoning that a human would raise the cap and resume, which is true at a
|
|
42
|
+
terminal and false inside a Job: there is no human, so a build stopped mid-work
|
|
43
|
+
by the cost breaker was reported as a success. Exit 0 must mean the work is
|
|
44
|
+
finished or a person chose to stop it.
|
|
45
|
+
|
|
46
|
+
Helm wires this up for you: `worker.exitCodes.terminalFailure` (default 20)
|
|
47
|
+
feeds the Job's `podFailurePolicy`, so a deterministic failure fails the Job
|
|
48
|
+
immediately instead of burning `backoffLimit`. Requires Kubernetes 1.31+.
|
|
49
|
+
|
|
50
|
+
Both the bash runner and the Bun runner (`LOKI_SDK_LOOP`) implement this
|
|
51
|
+
identically; a parity test asserts they agree status for status.
|
|
52
|
+
|
|
53
|
+
## `loki verify`
|
|
54
|
+
|
|
55
|
+
| Code | Verdict |
|
|
56
|
+
|---|---|
|
|
57
|
+
| 0 | VERIFIED |
|
|
58
|
+
| 1 | CONCERNS (findings below the block threshold, or inconclusive evidence) |
|
|
59
|
+
| 2 | BLOCKED (findings at or above the block threshold) |
|
|
60
|
+
| 3 | Verifier error: it could not complete, and never silently passes |
|
|
61
|
+
|
|
62
|
+
Code 3 matters more than it looks. A verifier that cannot run is not a pass,
|
|
63
|
+
so `[ $rc -eq 0 ]` is the only safe test for "verified" -- `[ $rc -ne 2 ]`
|
|
64
|
+
would treat a broken verifier as acceptable.
|
|
65
|
+
|
|
66
|
+
An early draft spec listed `1=BLOCKED, 2=CONCERNS`. That ordering was rejected:
|
|
67
|
+
it is not used anywhere, it has no consumers, and it inverts the
|
|
68
|
+
severity-rises-with-the-code rule that every other command follows.
|
|
69
|
+
|
|
70
|
+
## `loki ci`
|
|
71
|
+
|
|
72
|
+
| Code | Meaning |
|
|
73
|
+
|---|---|
|
|
74
|
+
| 0 | Passed, or all findings are below `--fail-on` |
|
|
75
|
+
| 1 | Findings exceed the `--fail-on` threshold |
|
|
76
|
+
| 2 | Error: missing tools or invalid arguments |
|
|
77
|
+
|
|
78
|
+
Machine-readable output is `--format json` here, not `--json`.
|
|
79
|
+
|
|
80
|
+
## `loki doctor`
|
|
81
|
+
|
|
82
|
+
| Code | Meaning |
|
|
83
|
+
|---|---|
|
|
84
|
+
| 0 | Every required check passed. Optional warnings do not fail the command. |
|
|
85
|
+
| nonzero | At least one required check failed; the output names which |
|
|
86
|
+
|
|
87
|
+
Safe as a preflight gate in an init container or pipeline step:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
loki doctor || { echo "host is not ready"; exit 1; }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
An absent optional provider CLI is a warning, not a blocker, so this will not
|
|
94
|
+
refuse to start over a tool you were never going to use.
|
|
95
|
+
|
|
96
|
+
## Security scan
|
|
97
|
+
|
|
98
|
+
| Code | Meaning |
|
|
99
|
+
|---|---|
|
|
100
|
+
| 0 | No high or critical findings |
|
|
101
|
+
| 1 | At least one HIGH |
|
|
102
|
+
| 2 | At least one CRITICAL |
|
|
103
|
+
|
|
104
|
+
## Signals
|
|
105
|
+
|
|
106
|
+
`loki start` handles the usual terminating signals conventionally: 130 for
|
|
107
|
+
SIGINT (Ctrl-C), 143 for SIGTERM. Under the durable contract these are crashes
|
|
108
|
+
in the retryable sense -- a pod terminated by the scheduler resumes rather than
|
|
109
|
+
being treated as a completed build.
|
|
110
|
+
|
|
111
|
+
## Writing a gate
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
# Block a merge unless verification is clean. Note -ne 0, not -eq 2:
|
|
115
|
+
# a verifier ERROR (3) must not pass.
|
|
116
|
+
loki verify || { echo "not verified"; exit 1; }
|
|
117
|
+
|
|
118
|
+
# Kubernetes: let the platform decide whether to retry.
|
|
119
|
+
LOKI_DURABLE_STATE=1 loki start ./prd.md
|
|
120
|
+
rc=$?
|
|
121
|
+
case $rc in
|
|
122
|
+
0) echo "complete" ;;
|
|
123
|
+
20) echo "terminal failure -- fix the spec or raise the budget, then re-submit" ;;
|
|
124
|
+
*) echo "crashed (rc=$rc) -- resume is safe" ;;
|
|
125
|
+
esac
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Do not read an exit code through a pipe. `$?` after a pipeline reports the last
|
|
129
|
+
stage, so `loki verify | tee log` gives you `tee`'s status and always looks
|
|
130
|
+
successful. Use `${PIPESTATUS[0]}` in bash, or capture first and test after.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Verifying the container image
|
|
2
|
+
|
|
3
|
+
Everything on this page is a command you run against the public registry and
|
|
4
|
+
the public sigstore transparency log. None of it requires an account with us,
|
|
5
|
+
and none of it trusts anything we say here: if a command below fails, the
|
|
6
|
+
correct conclusion is that the image is not what we claim, not that the
|
|
7
|
+
instructions are stale.
|
|
8
|
+
|
|
9
|
+
## What is covered, and from which version
|
|
10
|
+
|
|
11
|
+
Read this section before the commands. Provenance that claims more than it
|
|
12
|
+
delivers is worse than none, because it is exactly what an auditor will test.
|
|
13
|
+
|
|
14
|
+
| Artifact | Signature | SBOM |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| Container image (`asklokesh/loki-mode`) | first release after v8.5.2 | first release after v8.5.2 |
|
|
17
|
+
| npm tarball (`loki-mode`) | v7.4.10 and later | v7.4.10 and later |
|
|
18
|
+
|
|
19
|
+
**Images published up to and including v8.5.2 are not signed and have no SBOM.** A signing
|
|
20
|
+
workflow existed from v7.4.10 but was triggered on `release: published`, and
|
|
21
|
+
because our releases are created by a workflow using the default
|
|
22
|
+
`GITHUB_TOKEN`, GitHub never emitted that event. The workflow therefore never
|
|
23
|
+
ran on a real release, which the registry confirms: no `sha256-*.sig` tags
|
|
24
|
+
existed for any version through v8.5.2. Signing now runs inside the same job
|
|
25
|
+
that pushes the image, so it cannot be skipped by a trigger that does not fire.
|
|
26
|
+
|
|
27
|
+
We are not backfilling signatures for older tags. A signature applied today by
|
|
28
|
+
a different pipeline than the one that built the artifact months ago attests
|
|
29
|
+
to far less than it appears to, and the appearance is the dangerous part.
|
|
30
|
+
|
|
31
|
+
## Verify the signature
|
|
32
|
+
|
|
33
|
+
Requires [cosign](https://github.com/sigstore/cosign) v2.x. Substitute your
|
|
34
|
+
version for `8.6.0`.
|
|
35
|
+
|
|
36
|
+
Signatures are bound to the image **digest**, not to a tag. Tags are mutable --
|
|
37
|
+
`latest` moves every release, and even a version tag can be repointed -- so
|
|
38
|
+
resolve the digest first and verify that.
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
VERSION=8.6.0 # or whichever release first carried signing; see the table above
|
|
42
|
+
DIGEST=$(docker buildx imagetools inspect "asklokesh/loki-mode:${VERSION}" \
|
|
43
|
+
--format '{{json .Manifest.Digest}}' | tr -d '"')
|
|
44
|
+
echo "$DIGEST"
|
|
45
|
+
|
|
46
|
+
cosign verify \
|
|
47
|
+
--certificate-identity-regexp 'https://github.com/asklokesh/loki-mode/.github/workflows/release.yml@.*' \
|
|
48
|
+
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
|
|
49
|
+
"asklokesh/loki-mode@${DIGEST}"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The two `--certificate-*` flags are the part that matters, and omitting them
|
|
53
|
+
is the most common way to get a meaningless pass. Keyless signing means anyone
|
|
54
|
+
with a GitHub account can produce a valid sigstore signature over our image;
|
|
55
|
+
what makes the signature *ours* is that it was issued to our workflow identity
|
|
56
|
+
by GitHub's OIDC issuer. Without those flags cosign will happily confirm that
|
|
57
|
+
the image was signed by somebody.
|
|
58
|
+
|
|
59
|
+
A pass prints a JSON block including the certificate's subject, which should
|
|
60
|
+
name `release.yml` in this repository.
|
|
61
|
+
|
|
62
|
+
## Verify and read the SBOM
|
|
63
|
+
|
|
64
|
+
The SBOM is attached to the image as a CycloneDX attestation. Note this is a
|
|
65
|
+
*separate* artifact from the npm SBOM published on the GitHub Release: the
|
|
66
|
+
image carries an OS layer, a Python runtime and system packages that the npm
|
|
67
|
+
tarball's SBOM never described. If you are deploying by Helm, ECS, or any
|
|
68
|
+
other image-based path, the image SBOM is the one that matches what you run.
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
cosign verify-attestation \
|
|
72
|
+
--type cyclonedx \
|
|
73
|
+
--certificate-identity-regexp 'https://github.com/asklokesh/loki-mode/.github/workflows/release.yml@.*' \
|
|
74
|
+
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
|
|
75
|
+
"asklokesh/loki-mode@${DIGEST}" \
|
|
76
|
+
| jq -r '.payload' | base64 -d | jq '.predicate' > image-sbom.cdx.json
|
|
77
|
+
|
|
78
|
+
jq '.components | length' image-sbom.cdx.json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`verify-attestation` checks the signature over the SBOM before you read it,
|
|
82
|
+
which is the point: an SBOM you downloaded unverified tells you what someone
|
|
83
|
+
wanted you to believe is in the image.
|
|
84
|
+
|
|
85
|
+
**Scope limit worth knowing.** We publish a multi-arch image (linux/amd64 and
|
|
86
|
+
linux/arm64). The signature covers the manifest list, so it covers both
|
|
87
|
+
architectures. The SBOM does not: it is generated from a single resolved
|
|
88
|
+
platform, so package versions specific to the other architecture may differ
|
|
89
|
+
from what it lists. If you deploy on arm64 and need an exact bill of materials
|
|
90
|
+
for that architecture, generate it against the arch-specific digest yourself:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
syft "asklokesh/loki-mode:${VERSION}" --platform linux/arm64 -o cyclonedx-json
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Feed `image-sbom.cdx.json` to Grype, Trivy, Dependency-Track or any other
|
|
97
|
+
CycloneDX consumer for CVE scanning.
|
|
98
|
+
|
|
99
|
+
## Air-gapped environments
|
|
100
|
+
|
|
101
|
+
Both commands above reach the public sigstore infrastructure (Rekor and
|
|
102
|
+
Fulcio) to check the transparency log. To verify inside an air-gapped network,
|
|
103
|
+
mirror the trust root and the artifacts on a connected host first:
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
cosign save "asklokesh/loki-mode@${DIGEST}" --dir ./loki-image-bundle
|
|
107
|
+
cosign initialize --mirror <your-tuf-mirror> --root <your-root.json>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Then transfer `loki-image-bundle/` and verify with `cosign verify --local-image
|
|
111
|
+
./loki-image-bundle`. See `loki doctor --airgap` for the full host inventory
|
|
112
|
+
the engine itself needs at runtime.
|
|
113
|
+
|
|
114
|
+
## If verification fails
|
|
115
|
+
|
|
116
|
+
Do not deploy the image. In order of likelihood:
|
|
117
|
+
|
|
118
|
+
1. **You verified a tag instead of a digest.** Re-resolve the digest.
|
|
119
|
+
2. **You omitted the `--certificate-*` flags**, verified a digest that was
|
|
120
|
+
never ours, and got a pass or a confusing mismatch. Both flags are required.
|
|
121
|
+
3. **The version is v8.5.2 or earlier.** See the coverage table above; those images
|
|
122
|
+
are genuinely unsigned and no command will make them verify.
|
|
123
|
+
4. **The image is not what we published.** Report it at
|
|
124
|
+
https://github.com/asklokesh/loki-mode/issues and do not run it.
|