loki-mode 7.27.0 → 7.28.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 +3 -2
- package/SKILL.md +11 -2
- package/VERSION +1 -1
- package/autonomy/completion-council.sh +285 -6
- package/autonomy/context-tracker.py +32 -7
- package/autonomy/grill.sh +321 -0
- package/autonomy/loki +49 -0
- package/autonomy/prd-checklist.sh +248 -14
- package/autonomy/run.sh +170 -27
- package/autonomy/spec.sh +646 -0
- package/autonomy/verify.sh +55 -0
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +2 -1
- package/skills/quality-gates.md +46 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# autonomy/grill.sh - Loki spec interrogation (loki grill).
|
|
3
|
+
#
|
|
4
|
+
# Net-new capability (internal/SDD-PANEL-A.md ranks it HIGHEST: no Claude Code
|
|
5
|
+
# equivalent, no Loki equivalent). It exposes the Devil's-Advocate /
|
|
6
|
+
# anti-sycophancy posture that today fires only INSIDE the build loop
|
|
7
|
+
# (run.sh:7807) as a standalone PRE-build interrogation of a spec.
|
|
8
|
+
#
|
|
9
|
+
# What it does: invokes the provider ONCE (claude -p, the same single-shot
|
|
10
|
+
# pattern used for in-loop adversarial review and the haiku USAGE regen at
|
|
11
|
+
# run.sh:9832) with a Devil's-Advocate prompt that produces the 10-15 hardest
|
|
12
|
+
# questions exposing ambiguities, missing acceptance criteria, unstated
|
|
13
|
+
# assumptions, and security/scale blind spots. Output is a structured markdown
|
|
14
|
+
# report at .loki/grill/report.md. With --apply it appends a "Grill findings"
|
|
15
|
+
# section to the spec itself.
|
|
16
|
+
#
|
|
17
|
+
# Honest about provider dependency: requires the provider CLI; clean error when
|
|
18
|
+
# absent (no fabricated questions, no silent success).
|
|
19
|
+
#
|
|
20
|
+
# Spec source resolution (first match wins, same as loki spec):
|
|
21
|
+
# 1. explicit path argument
|
|
22
|
+
# 2. prd.md
|
|
23
|
+
# 3. .loki/generated-prd.md
|
|
24
|
+
# 4. PRD.md
|
|
25
|
+
# 5. docs/prd.md
|
|
26
|
+
#
|
|
27
|
+
# Exit codes:
|
|
28
|
+
# 0 report written
|
|
29
|
+
# 2 usage / spec-not-found error
|
|
30
|
+
# 3 provider unavailable or interrogation failed (never silent)
|
|
31
|
+
|
|
32
|
+
set -uo pipefail
|
|
33
|
+
|
|
34
|
+
GRILL_EXIT_OK=0
|
|
35
|
+
GRILL_EXIT_USAGE=2
|
|
36
|
+
GRILL_EXIT_ERROR=3
|
|
37
|
+
|
|
38
|
+
GRILL_DIR_DEFAULT=".loki/grill"
|
|
39
|
+
GRILL_REPORT_NAME="report.md"
|
|
40
|
+
|
|
41
|
+
_grill_log() { printf '[grill] %s\n' "$*" >&2; }
|
|
42
|
+
_grill_err() { printf '[grill][error] %s\n' "$*" >&2; }
|
|
43
|
+
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
# Resolve the spec source path. Echoes the path on success, empty on failure.
|
|
46
|
+
# Default order favors a hand-written prd.md over a generated one for grilling,
|
|
47
|
+
# since grilling is a pre-build hardening step on the human's intent.
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
grill_resolve_source() {
|
|
50
|
+
local explicit="${1:-}"
|
|
51
|
+
if [ -n "$explicit" ]; then
|
|
52
|
+
if [ -f "$explicit" ]; then
|
|
53
|
+
printf '%s\n' "$explicit"
|
|
54
|
+
return 0
|
|
55
|
+
fi
|
|
56
|
+
return 1
|
|
57
|
+
fi
|
|
58
|
+
local candidate
|
|
59
|
+
for candidate in \
|
|
60
|
+
"prd.md" \
|
|
61
|
+
".loki/generated-prd.md" \
|
|
62
|
+
"PRD.md" \
|
|
63
|
+
"docs/prd.md"; do
|
|
64
|
+
if [ -f "$candidate" ]; then
|
|
65
|
+
printf '%s\n' "$candidate"
|
|
66
|
+
return 0
|
|
67
|
+
fi
|
|
68
|
+
done
|
|
69
|
+
return 1
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
# Build the Devil's-Advocate interrogation prompt for a given spec body.
|
|
74
|
+
# ---------------------------------------------------------------------------
|
|
75
|
+
grill_build_prompt() {
|
|
76
|
+
local spec_path="$1"
|
|
77
|
+
local spec_body="$2"
|
|
78
|
+
cat <<EOF
|
|
79
|
+
You are a Devil's Advocate spec reviewer. Your job is to interrogate the
|
|
80
|
+
following specification and surface its weaknesses BEFORE any code is written.
|
|
81
|
+
Do not praise it. Do not summarize it. Do not propose an implementation.
|
|
82
|
+
|
|
83
|
+
Produce the 10 to 15 HARDEST questions that expose:
|
|
84
|
+
- ambiguities and underspecified behavior
|
|
85
|
+
- missing or untestable acceptance criteria
|
|
86
|
+
- unstated assumptions and implicit requirements
|
|
87
|
+
- security blind spots (authn/authz, input validation, secrets, data exposure)
|
|
88
|
+
- scale and reliability blind spots (concurrency, failure modes, limits)
|
|
89
|
+
- edge cases the spec does not address
|
|
90
|
+
|
|
91
|
+
Output STRICT markdown in exactly this shape and nothing else:
|
|
92
|
+
|
|
93
|
+
## Grill findings
|
|
94
|
+
|
|
95
|
+
### Ambiguities and missing acceptance criteria
|
|
96
|
+
1. <hard question>
|
|
97
|
+
2. <hard question>
|
|
98
|
+
|
|
99
|
+
### Unstated assumptions
|
|
100
|
+
1. <hard question>
|
|
101
|
+
|
|
102
|
+
### Security blind spots
|
|
103
|
+
1. <hard question>
|
|
104
|
+
|
|
105
|
+
### Scale and reliability blind spots
|
|
106
|
+
1. <hard question>
|
|
107
|
+
|
|
108
|
+
Each question must be specific to THIS spec (quote or reference the relevant
|
|
109
|
+
part), answerable, and uncomfortable. Total questions across all sections: 10
|
|
110
|
+
to 15. If a category has no real issue, write "None identified." under it
|
|
111
|
+
rather than padding.
|
|
112
|
+
|
|
113
|
+
=== SPEC: $spec_path ===
|
|
114
|
+
$spec_body
|
|
115
|
+
=== END SPEC ===
|
|
116
|
+
EOF
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# ---------------------------------------------------------------------------
|
|
120
|
+
# Invoke the provider once and capture the interrogation report.
|
|
121
|
+
# Echoes the report markdown on success; returns nonzero on failure.
|
|
122
|
+
# ---------------------------------------------------------------------------
|
|
123
|
+
# LOW-6: validate the provider (the same checks that produce rc=3) WITHOUT
|
|
124
|
+
# invoking it, so grill_main can fail cleanly BEFORE logging "interrogating ...
|
|
125
|
+
# via <provider>". Returns 0 if the provider is supported and its CLI is present;
|
|
126
|
+
# otherwise prints the same error grill_invoke_provider would and returns rc=3.
|
|
127
|
+
grill_check_provider() {
|
|
128
|
+
local provider="${LOKI_PROVIDER:-claude}"
|
|
129
|
+
case "$provider" in
|
|
130
|
+
claude)
|
|
131
|
+
if ! command -v claude >/dev/null 2>&1; then
|
|
132
|
+
_grill_err "Claude Code CLI not found. Install: https://docs.anthropic.com/en/docs/claude-code"
|
|
133
|
+
return $GRILL_EXIT_ERROR
|
|
134
|
+
fi
|
|
135
|
+
;;
|
|
136
|
+
codex)
|
|
137
|
+
if ! command -v codex >/dev/null 2>&1; then
|
|
138
|
+
_grill_err "Codex CLI not found."
|
|
139
|
+
return $GRILL_EXIT_ERROR
|
|
140
|
+
fi
|
|
141
|
+
;;
|
|
142
|
+
*)
|
|
143
|
+
_grill_err "grill currently supports the claude and codex providers (got: $provider)"
|
|
144
|
+
return $GRILL_EXIT_ERROR
|
|
145
|
+
;;
|
|
146
|
+
esac
|
|
147
|
+
return 0
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
grill_invoke_provider() {
|
|
151
|
+
local prompt="$1"
|
|
152
|
+
local provider="${LOKI_PROVIDER:-claude}"
|
|
153
|
+
|
|
154
|
+
case "$provider" in
|
|
155
|
+
claude)
|
|
156
|
+
if ! command -v claude >/dev/null 2>&1; then
|
|
157
|
+
_grill_err "Claude Code CLI not found. Install: https://docs.anthropic.com/en/docs/claude-code"
|
|
158
|
+
return $GRILL_EXIT_ERROR
|
|
159
|
+
fi
|
|
160
|
+
local out
|
|
161
|
+
# Single-shot, non-interactive. Same pattern as the in-loop
|
|
162
|
+
# adversarial reviewer (run.sh:7807) and USAGE regen (run.sh:9832).
|
|
163
|
+
out="$(printf '%s' "$prompt" \
|
|
164
|
+
| timeout "${LOKI_GRILL_TIMEOUT:-180}" claude --dangerously-skip-permissions --model "${LOKI_GRILL_MODEL:-sonnet}" -p - 2>/dev/null)"
|
|
165
|
+
if [ -z "$out" ]; then
|
|
166
|
+
_grill_err "provider returned no output (timeout or invocation error)"
|
|
167
|
+
return $GRILL_EXIT_ERROR
|
|
168
|
+
fi
|
|
169
|
+
printf '%s\n' "$out"
|
|
170
|
+
return 0
|
|
171
|
+
;;
|
|
172
|
+
codex)
|
|
173
|
+
if ! command -v codex >/dev/null 2>&1; then
|
|
174
|
+
_grill_err "Codex CLI not found."
|
|
175
|
+
return $GRILL_EXIT_ERROR
|
|
176
|
+
fi
|
|
177
|
+
local out
|
|
178
|
+
out="$(printf '%s' "$prompt" | timeout "${LOKI_GRILL_TIMEOUT:-180}" codex exec --full-auto - 2>/dev/null)"
|
|
179
|
+
if [ -z "$out" ]; then
|
|
180
|
+
_grill_err "provider returned no output"
|
|
181
|
+
return $GRILL_EXIT_ERROR
|
|
182
|
+
fi
|
|
183
|
+
printf '%s\n' "$out"
|
|
184
|
+
return 0
|
|
185
|
+
;;
|
|
186
|
+
*)
|
|
187
|
+
_grill_err "grill currently supports the claude and codex providers (got: $provider)"
|
|
188
|
+
return $GRILL_EXIT_ERROR
|
|
189
|
+
;;
|
|
190
|
+
esac
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# ---------------------------------------------------------------------------
|
|
194
|
+
# Help
|
|
195
|
+
# ---------------------------------------------------------------------------
|
|
196
|
+
grill_help() {
|
|
197
|
+
cat <<'EOF'
|
|
198
|
+
loki grill - interrogate a spec with the hardest questions before you build it.
|
|
199
|
+
|
|
200
|
+
USAGE:
|
|
201
|
+
loki grill [<spec-path>] [options]
|
|
202
|
+
|
|
203
|
+
DESCRIPTION:
|
|
204
|
+
Invokes the provider once with a Devil's-Advocate prompt to produce the
|
|
205
|
+
10-15 hardest questions exposing ambiguities, missing acceptance criteria,
|
|
206
|
+
unstated assumptions, and security/scale blind spots in a spec. Writes a
|
|
207
|
+
structured markdown report to .loki/grill/report.md.
|
|
208
|
+
|
|
209
|
+
This is a PRE-build hardening step: a grilled spec is a better Reason input
|
|
210
|
+
to the RARV-C loop. It requires the provider CLI and fails cleanly (no
|
|
211
|
+
fabricated questions) when the provider is unavailable.
|
|
212
|
+
|
|
213
|
+
SPEC RESOLUTION (when <spec-path> is omitted, first match wins):
|
|
214
|
+
prd.md -> .loki/generated-prd.md -> PRD.md -> docs/prd.md
|
|
215
|
+
|
|
216
|
+
OPTIONS:
|
|
217
|
+
--apply Append the "Grill findings" section to the spec file itself.
|
|
218
|
+
--out <dir> Output directory for the report. Default: .loki/grill
|
|
219
|
+
-h, --help Show this help.
|
|
220
|
+
|
|
221
|
+
ENVIRONMENT:
|
|
222
|
+
LOKI_PROVIDER Provider to use (claude default; codex supported).
|
|
223
|
+
LOKI_GRILL_MODEL Claude model for the interrogation (default: sonnet).
|
|
224
|
+
LOKI_GRILL_TIMEOUT Per-invocation timeout in seconds (default: 180).
|
|
225
|
+
|
|
226
|
+
EXIT CODES:
|
|
227
|
+
0 report written
|
|
228
|
+
2 usage error (spec not found)
|
|
229
|
+
3 provider unavailable or interrogation failed (never silent)
|
|
230
|
+
|
|
231
|
+
OUTPUT:
|
|
232
|
+
<out>/report.md the structured interrogation report
|
|
233
|
+
EOF
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
# ---------------------------------------------------------------------------
|
|
237
|
+
# Entry point
|
|
238
|
+
# ---------------------------------------------------------------------------
|
|
239
|
+
grill_main() {
|
|
240
|
+
local spec_arg=""
|
|
241
|
+
local out_dir="$GRILL_DIR_DEFAULT"
|
|
242
|
+
local apply="false"
|
|
243
|
+
|
|
244
|
+
while [ $# -gt 0 ]; do
|
|
245
|
+
case "$1" in
|
|
246
|
+
-h|--help) grill_help; return $GRILL_EXIT_OK ;;
|
|
247
|
+
--apply) apply="true"; shift ;;
|
|
248
|
+
--out) out_dir="${2:-}"; shift 2 ;;
|
|
249
|
+
--) shift; break ;;
|
|
250
|
+
-*) _grill_err "unknown option: $1"; grill_help; return $GRILL_EXIT_USAGE ;;
|
|
251
|
+
*)
|
|
252
|
+
if [ -z "$spec_arg" ]; then spec_arg="$1"; else
|
|
253
|
+
_grill_err "unexpected argument: $1"; return $GRILL_EXIT_USAGE
|
|
254
|
+
fi
|
|
255
|
+
shift ;;
|
|
256
|
+
esac
|
|
257
|
+
done
|
|
258
|
+
|
|
259
|
+
local spec_path
|
|
260
|
+
if ! spec_path="$(grill_resolve_source "$spec_arg")"; then
|
|
261
|
+
if [ -n "$spec_arg" ]; then
|
|
262
|
+
_grill_err "spec file not found: $spec_arg"
|
|
263
|
+
else
|
|
264
|
+
_grill_err "no spec found (looked for prd.md, .loki/generated-prd.md, PRD.md, docs/prd.md). Pass a path explicitly."
|
|
265
|
+
fi
|
|
266
|
+
return $GRILL_EXIT_USAGE
|
|
267
|
+
fi
|
|
268
|
+
|
|
269
|
+
local spec_body
|
|
270
|
+
spec_body="$(cat "$spec_path" 2>/dev/null)"
|
|
271
|
+
if [ -z "$spec_body" ]; then
|
|
272
|
+
_grill_err "spec file is empty: $spec_path"
|
|
273
|
+
return $GRILL_EXIT_USAGE
|
|
274
|
+
fi
|
|
275
|
+
|
|
276
|
+
# LOW-6: validate the provider BEFORE logging the interrogation line, so an
|
|
277
|
+
# unavailable/unsupported provider fails cleanly (rc=3) without first printing
|
|
278
|
+
# a misleading "interrogating ... via <provider>" message.
|
|
279
|
+
grill_check_provider || return $GRILL_EXIT_ERROR
|
|
280
|
+
|
|
281
|
+
local prompt
|
|
282
|
+
prompt="$(grill_build_prompt "$spec_path" "$spec_body")"
|
|
283
|
+
|
|
284
|
+
_grill_log "interrogating $spec_path via ${LOKI_PROVIDER:-claude}..."
|
|
285
|
+
local report
|
|
286
|
+
report="$(grill_invoke_provider "$prompt")" || return $GRILL_EXIT_ERROR
|
|
287
|
+
|
|
288
|
+
mkdir -p "$out_dir" || { _grill_err "cannot create $out_dir"; return $GRILL_EXIT_ERROR; }
|
|
289
|
+
local report_path="$out_dir/$GRILL_REPORT_NAME"
|
|
290
|
+
|
|
291
|
+
{
|
|
292
|
+
printf '# Spec grill report\n\n'
|
|
293
|
+
# printf format strings must not begin with '-': bash's printf builtin
|
|
294
|
+
# parses a leading dash as an option flag (rc=2 "invalid option") and
|
|
295
|
+
# silently drops the line. Use '%s\n' with the dash inside the argument.
|
|
296
|
+
printf '%s\n' "- Spec: $spec_path"
|
|
297
|
+
printf '%s\n' "- Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
298
|
+
printf '%s\n\n' "- Provider: ${LOKI_PROVIDER:-claude}"
|
|
299
|
+
printf '%s\n' "$report"
|
|
300
|
+
} >"$report_path" || { _grill_err "failed to write $report_path"; return $GRILL_EXIT_ERROR; }
|
|
301
|
+
|
|
302
|
+
_grill_log "report written: $report_path"
|
|
303
|
+
printf 'Grill report: %s\n' "$report_path"
|
|
304
|
+
|
|
305
|
+
if [ "$apply" = "true" ]; then
|
|
306
|
+
{
|
|
307
|
+
printf '\n\n<!-- loki grill: appended %s -->\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
308
|
+
printf '%s\n' "$report"
|
|
309
|
+
} >>"$spec_path" || { _grill_err "failed to append findings to $spec_path"; return $GRILL_EXIT_ERROR; }
|
|
310
|
+
_grill_log "appended Grill findings to $spec_path"
|
|
311
|
+
printf 'Appended Grill findings to: %s\n' "$spec_path"
|
|
312
|
+
fi
|
|
313
|
+
|
|
314
|
+
return $GRILL_EXIT_OK
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
# Allow direct execution: bash autonomy/grill.sh [args]
|
|
318
|
+
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
|
|
319
|
+
grill_main "$@"
|
|
320
|
+
exit $?
|
|
321
|
+
fi
|
package/autonomy/loki
CHANGED
|
@@ -555,6 +555,8 @@ show_help() {
|
|
|
555
555
|
echo " audit [cmd] Agent audit log and quality scanning (log|scan)"
|
|
556
556
|
echo " heal <path> Legacy system healing (archaeology, stabilize, modernize)"
|
|
557
557
|
echo " verify [base] Deterministic PR verification (Autonomi Verify MVP; CI-gate exit codes)"
|
|
558
|
+
echo " spec [cmd] Living spec: keep the spec true (lock|status|sync; drift detection, CI-gate exit codes)"
|
|
559
|
+
echo " grill [spec] Interrogate a spec with the hardest questions before you build it (Devil's Advocate)"
|
|
558
560
|
echo " review [opts] Standalone code review with quality gates (diff, staged, PR, files)"
|
|
559
561
|
echo " optimize Optimize prompts based on session history"
|
|
560
562
|
echo " enterprise Enterprise feature management (tokens, OIDC)"
|
|
@@ -11380,6 +11382,47 @@ cmd_verify() {
|
|
|
11380
11382
|
return $?
|
|
11381
11383
|
}
|
|
11382
11384
|
|
|
11385
|
+
# ---------------------------------------------------------------------------
|
|
11386
|
+
# loki spec - the living spec (drift detection + lock)
|
|
11387
|
+
#
|
|
11388
|
+
# Thin dispatcher that sources autonomy/spec.sh and delegates to spec_main().
|
|
11389
|
+
# The spec core is deliberately standalone (it does NOT enter the autonomous
|
|
11390
|
+
# loop): it binds spec requirements to content hashes (.loki/spec/spec.lock)
|
|
11391
|
+
# and detects drift deterministically, emitting .loki/spec/drift-report.json.
|
|
11392
|
+
# Exit codes are propagated so `loki spec status` is CI-gate usable.
|
|
11393
|
+
# ---------------------------------------------------------------------------
|
|
11394
|
+
cmd_spec() {
|
|
11395
|
+
local spec_mod="$_LOKI_SCRIPT_DIR/spec.sh"
|
|
11396
|
+
if [ ! -f "$spec_mod" ]; then
|
|
11397
|
+
echo -e "${RED}Error: spec module not found at $spec_mod${NC}" >&2
|
|
11398
|
+
return 3
|
|
11399
|
+
fi
|
|
11400
|
+
# shellcheck source=/dev/null
|
|
11401
|
+
source "$spec_mod"
|
|
11402
|
+
spec_main "$@"
|
|
11403
|
+
return $?
|
|
11404
|
+
}
|
|
11405
|
+
|
|
11406
|
+
# ---------------------------------------------------------------------------
|
|
11407
|
+
# loki grill - spec interrogation (Devil's-Advocate, pre-build)
|
|
11408
|
+
#
|
|
11409
|
+
# Thin dispatcher that sources autonomy/grill.sh and delegates to grill_main().
|
|
11410
|
+
# Invokes the provider once to produce the hardest questions exposing spec
|
|
11411
|
+
# weaknesses; writes .loki/grill/report.md. Requires the provider CLI and
|
|
11412
|
+
# fails cleanly when it is absent (no fabricated questions).
|
|
11413
|
+
# ---------------------------------------------------------------------------
|
|
11414
|
+
cmd_grill() {
|
|
11415
|
+
local grill_mod="$_LOKI_SCRIPT_DIR/grill.sh"
|
|
11416
|
+
if [ ! -f "$grill_mod" ]; then
|
|
11417
|
+
echo -e "${RED}Error: grill module not found at $grill_mod${NC}" >&2
|
|
11418
|
+
return 3
|
|
11419
|
+
fi
|
|
11420
|
+
# shellcheck source=/dev/null
|
|
11421
|
+
source "$grill_mod"
|
|
11422
|
+
grill_main "$@"
|
|
11423
|
+
return $?
|
|
11424
|
+
}
|
|
11425
|
+
|
|
11383
11426
|
cmd_heal_help() {
|
|
11384
11427
|
echo -e "${BOLD}loki heal${NC} - Legacy system healing (v6.67.0)"
|
|
11385
11428
|
echo ""
|
|
@@ -13530,6 +13573,12 @@ main() {
|
|
|
13530
13573
|
verify)
|
|
13531
13574
|
cmd_verify "$@"
|
|
13532
13575
|
;;
|
|
13576
|
+
spec)
|
|
13577
|
+
cmd_spec "$@"
|
|
13578
|
+
;;
|
|
13579
|
+
grill)
|
|
13580
|
+
cmd_grill "$@"
|
|
13581
|
+
;;
|
|
13533
13582
|
migrate)
|
|
13534
13583
|
cmd_migrate "$@"
|
|
13535
13584
|
;;
|