loki-mode 9.16.0 → 9.17.2
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/issue-providers.sh +0 -21
- package/autonomy/lib/verdict.py +4 -25
- package/autonomy/loki +4 -190
- package/autonomy/run.sh +64 -167
- package/autonomy/verify.sh +100 -12
- package/completions/_loki +0 -2
- package/completions/loki.bash +1 -1
- package/dashboard/__init__.py +1 -1
- package/dashboard/static/index.html +168 -2
- package/docs/VERIFICATION-COST.md +20 -0
- package/loki-ts/dist/loki.js +215 -215
- package/mcp/__init__.py +1 -1
- package/mcp/_sdk_loader.py +0 -25
- 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 v9.
|
|
6
|
+
# Loki Mode v9.17.2
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -470,4 +470,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
470
470
|
|
|
471
471
|
---
|
|
472
472
|
|
|
473
|
-
**v9.
|
|
473
|
+
**v9.17.2 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
9.
|
|
1
|
+
9.17.2
|
|
@@ -380,26 +380,6 @@ repo = data.get('repo', '')
|
|
|
380
380
|
|
|
381
381
|
labels_str = ', '.join(labels) if labels else ''
|
|
382
382
|
|
|
383
|
-
_ac_text = (title + ' ' + body).lower()
|
|
384
|
-
_ac_rules = [
|
|
385
|
-
(['save', 'persist', 'store', 'databas', 'crud'],
|
|
386
|
-
'Data the change writes survives a restart (a real store, not in-memory state).'),
|
|
387
|
-
(['auth', 'login', 'sign in', 'session', 'permission'],
|
|
388
|
-
'The auth path is exercised end to end including the denied case (401/403), not only the happy path.'),
|
|
389
|
-
(['api', 'endpoint', 'rest', 'graphql', 'route'],
|
|
390
|
-
'Each affected endpoint returns the documented status codes and is callable without a browser.'),
|
|
391
|
-
(['payment', 'stripe', 'billing', 'invoice', 'subscription'],
|
|
392
|
-
'The payment path runs against provider test mode; no mocked charge stands in for the integration.'),
|
|
393
|
-
(['bug', 'fix', 'regression', 'broken', 'crash', 'error'],
|
|
394
|
-
'A test reproduces the reported failure and FAILS before the fix, then passes after it.'),
|
|
395
|
-
(['perf', 'slow', 'latency', 'timeout', 'memory leak'],
|
|
396
|
-
'The improvement is measured before and after, and the numbers appear in the change.'),
|
|
397
|
-
(['security', 'vulnerab', 'injection', 'xss', 'csrf'],
|
|
398
|
-
'A test demonstrates the vulnerable behavior is refused after the change.'),
|
|
399
|
-
]
|
|
400
|
-
_hits = [c for kws, c in _ac_rules if any(k in _ac_text for k in kws)]
|
|
401
|
-
derived_ac = ('\n'.join('- ' + h for h in _hits) + '\n') if _hits else ''
|
|
402
|
-
|
|
403
383
|
prd = f'''# PRD: {title}
|
|
404
384
|
|
|
405
385
|
**Source:** {provider.replace('_', ' ').title()} Issue [{number}]({url})
|
|
@@ -428,7 +408,6 @@ Based on the issue description, implement the following:
|
|
|
428
408
|
2. Ensure backward compatibility (unless explicitly breaking changes are requested)
|
|
429
409
|
3. Add appropriate tests for new functionality
|
|
430
410
|
4. Update documentation as needed
|
|
431
|
-
{derived_ac}
|
|
432
411
|
|
|
433
412
|
---
|
|
434
413
|
|
package/autonomy/lib/verdict.py
CHANGED
|
@@ -91,25 +91,9 @@ def _authorship_line(loki_dir, run_id=None):
|
|
|
91
91
|
|
|
92
92
|
|
|
93
93
|
def _grounding_line(loki_dir):
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
|
|
97
|
-
# is UNKNOWN -- not a pass, and not a failure.
|
|
98
|
-
d = _read_json(os.path.join(loki_dir, "state", "claim-grounding.json"))
|
|
99
|
-
if not isinstance(d, dict) or d.get("status") != "measured":
|
|
100
|
-
return UNKNOWN, "no completion claim was checked against the diff"
|
|
101
|
-
named = d.get("paths_named") or []
|
|
102
|
-
if not named:
|
|
103
|
-
# Reported by name rather than scored: a claim naming no path is
|
|
104
|
-
# UNGROUNDABLE, which is a different fact from a claim that checked out.
|
|
105
|
-
return UNKNOWN, "the completion claim named no file path, so it cannot be grounded"
|
|
106
|
-
ungrounded = d.get("ungrounded") or []
|
|
107
|
-
if d.get("has_ungrounded_claim"):
|
|
108
|
-
return "finding", (
|
|
109
|
-
f"the completion claim names {len(ungrounded)} path(s) absent from the diff: "
|
|
110
|
-
+ ", ".join(str(p) for p in ungrounded[:3])
|
|
111
|
-
)
|
|
112
|
-
return "measured", f"all {len(named)} path(s) named in the completion claim are in the diff"
|
|
94
|
+
# Grounding is computed per claim at completion time, not stored, so this
|
|
95
|
+
# reports availability rather than inventing a stale result.
|
|
96
|
+
return UNKNOWN, "run `loki verify` to check the completion claim against the diff"
|
|
113
97
|
|
|
114
98
|
|
|
115
99
|
def _model_line(loki_dir):
|
|
@@ -177,12 +161,7 @@ def render_markdown(v):
|
|
|
177
161
|
out.append("| Signal | Status | Detail |")
|
|
178
162
|
out.append("|---|---|---|")
|
|
179
163
|
for r in v["signals"]:
|
|
180
|
-
|
|
181
|
-
# would render a real finding ("the claim names a file absent from the
|
|
182
|
-
# diff") identically to "we could not check" -- the false equivalence
|
|
183
|
-
# this whole module exists to refuse. Anything unrecognised still
|
|
184
|
-
# degrades to UNKNOWN, so an unmeasured signal can never read as a pass.
|
|
185
|
-
status = r["status"] if r["status"] in ("measured", "finding") else UNKNOWN
|
|
164
|
+
status = "measured" if r["status"] == "measured" else "UNKNOWN"
|
|
186
165
|
out.append(f"| {r['signal']} | {status} | {r['detail']} |")
|
|
187
166
|
out.append("")
|
|
188
167
|
out.append("Every line is derived from a file in `.loki/` that you can read "
|
package/autonomy/loki
CHANGED
|
@@ -1044,11 +1044,11 @@ show_help() {
|
|
|
1044
1044
|
echo " import init intent"
|
|
1045
1045
|
echo " issue kpis logs magic mcp memory metrics migrate modernize monitor"
|
|
1046
1046
|
echo " next notify onboard open optimize otel outcomes own (handoff) pause plan preview"
|
|
1047
|
-
echo " projects proof (receipt) provider quick quickstart rc
|
|
1047
|
+
echo " projects proof (receipt) provider quick quickstart rc remote report reset"
|
|
1048
1048
|
echo " resume review rollback run sandbox secrets secure self-update sentrux"
|
|
1049
1049
|
echo " serve setup-skill share ship spec start state stats status steer stop"
|
|
1050
1050
|
echo " syslog telemetry template test tour trigger trust trust-metrics"
|
|
1051
|
-
echo " ultracode update
|
|
1051
|
+
echo " ultracode update verify version voice watch watchdog web welcome why"
|
|
1052
1052
|
echo " wiki worktree (wt)"
|
|
1053
1053
|
echo ""
|
|
1054
1054
|
echo "Any command: loki <command> --help"
|
|
@@ -11905,14 +11905,7 @@ STALE_DAYS = 90
|
|
|
11905
11905
|
p = os.environ['LOKI_CATALOG_PATH']
|
|
11906
11906
|
try:
|
|
11907
11907
|
updated = json.load(open(p))['updated']
|
|
11908
|
-
|
|
11909
|
-
# (doctor.ts:545). This is the TEXT-mode twin of that computation, and it was
|
|
11910
|
-
# missed when the JSON one was fixed: the parity gate compares BOTH surfaces,
|
|
11911
|
-
# so fixing only --json left doctor text-mode still diverging 5 vs 6 and the
|
|
11912
|
-
# gate still red. Two copies of one calculation is the actual defect here;
|
|
11913
|
-
# they are left as two only because the text path prints and the JSON path
|
|
11914
|
-
# returns a dict.
|
|
11915
|
-
age = (datetime.datetime.now(datetime.timezone.utc).date() - datetime.date.fromisoformat(updated)).days
|
|
11908
|
+
age = (datetime.date.today() - datetime.date.fromisoformat(updated)).days
|
|
11916
11909
|
except Exception:
|
|
11917
11910
|
print('warn|Catalog unreadable or missing an ISO \"updated\" date -- cannot determine age')
|
|
11918
11911
|
else:
|
|
@@ -12036,17 +12029,6 @@ else:
|
|
|
12036
12029
|
local _blk_key="other"
|
|
12037
12030
|
case "$_doctor_blockers" in
|
|
12038
12031
|
*"No AI provider CLI"*) _blk_key="no_provider" ;;
|
|
12039
|
-
# This doctor DETECTS the logged-out / expired wall above
|
|
12040
|
-
# (:11610, :11615) but had no arm for it, so the single most
|
|
12041
|
-
# common post-install failure was reported as `other` -- the one
|
|
12042
|
-
# bucket that cannot be acted on. not_logged_in is already a
|
|
12043
|
-
# first-class enum value (telemetry.sh:204) and the Bun doctor
|
|
12044
|
-
# already reports it, so without this arm the SAME host answered
|
|
12045
|
-
# `other` on bash and `not_logged_in` on Bun and the two routes'
|
|
12046
|
-
# counts could not be added together. Ordered directly after
|
|
12047
|
-
# no_provider because install-vs-authenticate need opposite fixes
|
|
12048
|
-
# and a missing provider is the earlier wall.
|
|
12049
|
-
*"not logged in"*|*"login has expired"*) _blk_key="not_logged_in" ;;
|
|
12050
12032
|
*"Node.js is not installed"*|*"Node.js must be"*) _blk_key="node" ;;
|
|
12051
12033
|
*"Python 3 is not installed"*|*"Python 3 must be"*) _blk_key="python3" ;;
|
|
12052
12034
|
*"jq is not installed"*) _blk_key="jq" ;;
|
|
@@ -12330,18 +12312,7 @@ _cat_path = os.environ['LOKI_CATALOG_PATH']
|
|
|
12330
12312
|
try:
|
|
12331
12313
|
import datetime as _dt
|
|
12332
12314
|
_cat_updated = json.load(open(_cat_path))['updated']
|
|
12333
|
-
|
|
12334
|
-
# both sides at UTC midnight (doctor.ts:545 says so, to keep the day count
|
|
12335
|
-
# from shifting with the host timezone). Anywhere west of UTC the two
|
|
12336
|
-
# disagree for the hours between local midnight and UTC midnight, and
|
|
12337
|
-
# doctor --json is compared BYTE FOR BYTE between routes by bun-parity.
|
|
12338
|
-
#
|
|
12339
|
-
# Measured on this host at 02:45 UTC / 22:45 local: bash reported age_days 5
|
|
12340
|
-
# and Bun reported 6, from the same file at the same instant. It reproduced
|
|
12341
|
-
# across two full gate runs hours apart, so it is not a midnight-rollover
|
|
12342
|
-
# flake. It is a real parity defect that stays invisible while the local date
|
|
12343
|
-
# and the UTC date agree, which is most of the day.
|
|
12344
|
-
_cat_age = (_dt.datetime.now(_dt.timezone.utc).date() - _dt.date.fromisoformat(_cat_updated)).days
|
|
12315
|
+
_cat_age = (_dt.date.today() - _dt.date.fromisoformat(_cat_updated)).days
|
|
12345
12316
|
if _cat_age > CATALOG_STALE_DAYS:
|
|
12346
12317
|
# Deliberately NOT counted. The block comment above states catalog age is
|
|
12347
12318
|
# excluded from pass/fail/warn and from 'ok' so a stale catalog can never
|
|
@@ -13803,76 +13774,12 @@ set_ttfv_lightweight_profile() {
|
|
|
13803
13774
|
# never pollutes the v7.8.1 generated-PRD-reuse signature logic. The brief text
|
|
13804
13775
|
# is the project intent; the rest is a minimal scaffold the agent fills in.
|
|
13805
13776
|
# Usage: synthesize_brief_prd <output_file> <brief_text>
|
|
13806
|
-
# _brief_acceptance_criteria <brief_text>: acceptance criteria derived from what
|
|
13807
|
-
# the user ACTUALLY asked for, not constants.
|
|
13808
|
-
#
|
|
13809
|
-
# WHY. Every one-liner used to get byte-identical Requirements and Success
|
|
13810
|
-
# Criteria: "build a todo app" and "build a Stripe billing dashboard" produced
|
|
13811
|
-
# the same acceptance criteria, and the user's own words appeared exactly once,
|
|
13812
|
-
# under Overview. So the completion council, the checklist and the evidence gate
|
|
13813
|
-
# were all checking generic prose rather than the request. That is the weakest
|
|
13814
|
-
# input shape getting the least specific help, which is backwards -- a cheap
|
|
13815
|
-
# model's output quality depends more on how precisely the target is stated than
|
|
13816
|
-
# on the model.
|
|
13817
|
-
#
|
|
13818
|
-
# DETERMINISTIC ON PURPOSE. No model call: this runs before a provider is even
|
|
13819
|
-
# selected, must work with no API key, and must not add latency or cost to the
|
|
13820
|
-
# first thing a new user does. It is keyword-to-obligation mapping, which is
|
|
13821
|
-
# honest about being shallow -- it turns stated nouns into checkable lines and
|
|
13822
|
-
# claims nothing about intent it cannot see. Anything cleverer belongs in the
|
|
13823
|
-
# spec-interrogation grill, which already runs after this and does call a model.
|
|
13824
|
-
_brief_acceptance_criteria() {
|
|
13825
|
-
local t
|
|
13826
|
-
t="$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')"
|
|
13827
|
-
local out=""
|
|
13828
|
-
_bac() { out="${out}- ${1}"$'\n'; }
|
|
13829
|
-
|
|
13830
|
-
# Persistence. The single most common churn report is "I submitted the form
|
|
13831
|
-
# and nothing happened", so a stated store or form becomes an explicit
|
|
13832
|
-
# survives-a-reload obligation rather than an implied one.
|
|
13833
|
-
case "$t" in
|
|
13834
|
-
*save*|*persist*|*store*|*databas*|*crud*|*todo*|*note*|*task*|*record*)
|
|
13835
|
-
_bac "Data the user creates survives a page reload and a server restart (it is written to a real store, not held in memory)." ;;
|
|
13836
|
-
esac
|
|
13837
|
-
case "$t" in
|
|
13838
|
-
*form*|*submit*|*signup*|*"sign up"*|*contact*|*upload*|*checkout*)
|
|
13839
|
-
_bac "Every form actually submits: the happy path writes real data and the user sees a confirmation, and a validation failure shows an inline error." ;;
|
|
13840
|
-
esac
|
|
13841
|
-
case "$t" in
|
|
13842
|
-
*auth*|*login*|*"log in"*|*"sign in"*|*account*|*user*|*password*|*session*)
|
|
13843
|
-
_bac "Authentication works end to end: a real signup, a real login, and a protected route that returns 401 when logged out." ;;
|
|
13844
|
-
esac
|
|
13845
|
-
case "$t" in
|
|
13846
|
-
*api*|*endpoint*|*rest*|*graphql*|*backend*|*server*)
|
|
13847
|
-
_bac "Each endpoint returns real data with correct status codes, and is callable with curl without a browser." ;;
|
|
13848
|
-
esac
|
|
13849
|
-
case "$t" in
|
|
13850
|
-
*payment*|*stripe*|*billing*|*subscription*|*checkout*|*invoice*)
|
|
13851
|
-
_bac "The payment path is wired to the provider's test mode and a test transaction completes; no mocked charge stands in for the integration." ;;
|
|
13852
|
-
esac
|
|
13853
|
-
case "$t" in
|
|
13854
|
-
*search*|*filter*|*sort*)
|
|
13855
|
-
_bac "Search or filtering queries the real dataset and returns different results for different inputs." ;;
|
|
13856
|
-
esac
|
|
13857
|
-
case "$t" in
|
|
13858
|
-
*dashboard*|*chart*|*graph*|*analytic*|*report*|*metric*)
|
|
13859
|
-
_bac "Every figure shown traces to a real query. No hardcoded sample numbers." ;;
|
|
13860
|
-
esac
|
|
13861
|
-
case "$t" in
|
|
13862
|
-
*page*|*landing*|*site*|*website*|*ui*|*app*|*frontend*)
|
|
13863
|
-
_bac "The page renders with real content, no lorem ipsum, and no placeholder image where a real asset belongs." ;;
|
|
13864
|
-
esac
|
|
13865
|
-
printf '%s' "$out"
|
|
13866
|
-
}
|
|
13867
|
-
|
|
13868
13777
|
synthesize_brief_prd() {
|
|
13869
13778
|
local out_file="$1"
|
|
13870
13779
|
local brief_text="$2"
|
|
13871
13780
|
local out_dir
|
|
13872
13781
|
out_dir="$(dirname "$out_file")"
|
|
13873
13782
|
mkdir -p "$out_dir" 2>/dev/null || true
|
|
13874
|
-
local _derived
|
|
13875
|
-
_derived="$(_brief_acceptance_criteria "$brief_text")"
|
|
13876
13783
|
cat > "$out_file" << BRIEFEOF
|
|
13877
13784
|
# Project Brief
|
|
13878
13785
|
|
|
@@ -13888,7 +13795,6 @@ $brief_text
|
|
|
13888
13795
|
## Success Criteria
|
|
13889
13796
|
- A user can run the result and observe the core behavior described above.
|
|
13890
13797
|
- No errors on a clean start; the happy path works end to end.
|
|
13891
|
-
${_derived}
|
|
13892
13798
|
|
|
13893
13799
|
## Constraints
|
|
13894
13800
|
- This is a fast first pass (zero-config first run). Keep scope tight.
|
|
@@ -13990,10 +13896,6 @@ cmd_quick() {
|
|
|
13990
13896
|
find "$LOKI_DIR" -maxdepth 1 -name 'quick-prd-*.md' -mtime +1 -delete 2>/dev/null || true
|
|
13991
13897
|
find "$LOKI_DIR" -maxdepth 1 -name 'brief-prd-*.md' -mtime +1 -delete 2>/dev/null || true
|
|
13992
13898
|
local quick_prd="$LOKI_DIR/quick-prd-$$.md"
|
|
13993
|
-
# Same spec-derived criteria as the brief path: a quick task was getting the
|
|
13994
|
-
# identical generic Success Criteria regardless of what was asked.
|
|
13995
|
-
local _derived
|
|
13996
|
-
_derived="$(_brief_acceptance_criteria "$task_desc")"
|
|
13997
13899
|
cat > "$quick_prd" << QPRDEOF
|
|
13998
13900
|
# Quick Task
|
|
13999
13901
|
|
|
@@ -14010,7 +13912,6 @@ $task_desc
|
|
|
14010
13912
|
- Task is completed as described
|
|
14011
13913
|
- No errors or regressions introduced
|
|
14012
13914
|
- Code follows project conventions
|
|
14013
|
-
${_derived}
|
|
14014
13915
|
|
|
14015
13916
|
## Constraints
|
|
14016
13917
|
- This is a quick single-task execution
|
|
@@ -19475,15 +19376,6 @@ main() {
|
|
|
19475
19376
|
# happened to it afterwards -- reverted, reworked, or survived.
|
|
19476
19377
|
cmd_outcomes "$@"
|
|
19477
19378
|
;;
|
|
19478
|
-
verdict)
|
|
19479
|
-
# All five trust signals in one block. The individual measurements
|
|
19480
|
-
# existed and were unreachable; this is the surface a reviewer reads.
|
|
19481
|
-
cmd_verdict "$@"
|
|
19482
|
-
;;
|
|
19483
|
-
readiness)
|
|
19484
|
-
# Can an agent verify its own work here? Measured, not LLM-scored.
|
|
19485
|
-
cmd_readiness "$@"
|
|
19486
|
-
;;
|
|
19487
19379
|
secure)
|
|
19488
19380
|
# Secure-by-default gate surface: inspect findings + manage waivers.
|
|
19489
19381
|
cmd_secure "$@"
|
|
@@ -30959,84 +30851,6 @@ cmd_outcomes() {
|
|
|
30959
30851
|
LOKI_DIR="${LOKI_DIR:-.loki}" python3 "$lib" "$@"
|
|
30960
30852
|
}
|
|
30961
30853
|
|
|
30962
|
-
# loki verdict: the five measured trust signals, in one block a reviewer reads
|
|
30963
|
-
# in ten seconds.
|
|
30964
|
-
#
|
|
30965
|
-
# WHY A COMMAND AND NOT JUST A LIBRARY. We measure five things nobody else does
|
|
30966
|
-
# -- did the work survive, does the spec still match intent, was this the agent
|
|
30967
|
-
# or a human rescue, does the completion claim name real work, which model
|
|
30968
|
-
# decided -- and each was correct, tested, and unreachable. A moat nobody can
|
|
30969
|
-
# see is not a moat. This is the surface.
|
|
30970
|
-
#
|
|
30971
|
-
# There is deliberately NO composite score. Averaging a revert count, a hash
|
|
30972
|
-
# comparison, a diff hash, a path match and a model id yields a number whose
|
|
30973
|
-
# movement nobody can explain, which is what competitors already ship. UNKNOWN
|
|
30974
|
-
# is PRINTED, never suppressed: a reviewer must tell "we checked and it is fine"
|
|
30975
|
-
# from "we could not check". See autonomy/lib/verdict.py.
|
|
30976
|
-
cmd_verdict() {
|
|
30977
|
-
local lib="${_LOKI_SCRIPT_DIR}/lib/verdict.py"
|
|
30978
|
-
if [ ! -f "$lib" ]; then
|
|
30979
|
-
echo "verdict renderer is not installed at $lib" >&2
|
|
30980
|
-
return 2
|
|
30981
|
-
fi
|
|
30982
|
-
case "${1:-}" in
|
|
30983
|
-
--help|-h|help)
|
|
30984
|
-
echo -e "${BOLD}loki verdict${NC} - the five measured trust signals, in one readable block"
|
|
30985
|
-
echo ""
|
|
30986
|
-
echo "Usage: loki verdict [--json]"
|
|
30987
|
-
echo ""
|
|
30988
|
-
echo "Prints one line each for outcome, intent, authorship, grounding and"
|
|
30989
|
-
echo "model: what survived, whether the spec still matches intent, whether"
|
|
30990
|
-
echo "this was the agent or a human rescue, whether the completion claim"
|
|
30991
|
-
echo "named real work, and which model decided."
|
|
30992
|
-
echo ""
|
|
30993
|
-
echo "Every line is either a measured fact or an explicit UNKNOWN. There is"
|
|
30994
|
-
echo "no composite score: a number nobody can explain is not evidence."
|
|
30995
|
-
echo "Read-only: it never writes to the repo it analyses."
|
|
30996
|
-
return 0
|
|
30997
|
-
;;
|
|
30998
|
-
esac
|
|
30999
|
-
LOKI_DIR="${LOKI_DIR:-.loki}" python3 "$lib" "$@"
|
|
31000
|
-
}
|
|
31001
|
-
|
|
31002
|
-
# loki readiness: can an autonomous agent verify its own work in THIS repo?
|
|
31003
|
-
#
|
|
31004
|
-
# WHY THIS IS NOT A COPY OF FACTORY AI'S AGENT READINESS MODEL. Theirs is
|
|
31005
|
-
# LLM-scored -- their report objects record modelUsed and reasoningEffort, so
|
|
31006
|
-
# the number is a model's opinion and two runs can disagree about the same
|
|
31007
|
-
# commit. Every criterion here is a file that exists or does not, a command
|
|
31008
|
-
# present or absent: same commit, same answer, every machine, no key, no spend.
|
|
31009
|
-
#
|
|
31010
|
-
# No percentage and no letter grade. A composite invites ranking, ranking
|
|
31011
|
-
# invites gaming, and the individual signals are the actionable part -- "there
|
|
31012
|
-
# is no test command" tells you what to do, "readiness 62%" does not. Criteria
|
|
31013
|
-
# that cannot be determined report UNKNOWN by name rather than counting as
|
|
31014
|
-
# failures. See autonomy/lib/agent_readiness.py.
|
|
31015
|
-
cmd_readiness() {
|
|
31016
|
-
local lib="${_LOKI_SCRIPT_DIR}/lib/agent_readiness.py"
|
|
31017
|
-
if [ ! -f "$lib" ]; then
|
|
31018
|
-
echo "readiness assessor is not installed at $lib" >&2
|
|
31019
|
-
return 2
|
|
31020
|
-
fi
|
|
31021
|
-
case "${1:-}" in
|
|
31022
|
-
--help|-h|help)
|
|
31023
|
-
echo -e "${BOLD}loki readiness${NC} - can an agent verify its own work in this repo?"
|
|
31024
|
-
echo ""
|
|
31025
|
-
echo "Usage: loki readiness [path] [--json]"
|
|
31026
|
-
echo ""
|
|
31027
|
-
echo "Measures whether this repo gives an agent a way to check itself: a"
|
|
31028
|
-
echo "test command, a build, CI config, typed sources, a lockfile. Not"
|
|
31029
|
-
echo "general code quality -- the narrower question every agent depends on."
|
|
31030
|
-
echo ""
|
|
31031
|
-
echo "Deterministic: no model, no key, no spend. Same commit, same answer."
|
|
31032
|
-
echo "Criteria that cannot be determined report UNKNOWN rather than failing."
|
|
31033
|
-
echo "Read-only: it never writes to the repo it analyses."
|
|
31034
|
-
return 0
|
|
31035
|
-
;;
|
|
31036
|
-
esac
|
|
31037
|
-
python3 "$lib" "$@"
|
|
31038
|
-
}
|
|
31039
|
-
|
|
31040
30854
|
cmd_wiki() {
|
|
31041
30855
|
local subcmd="${1:-}"
|
|
31042
30856
|
shift 2>/dev/null || true
|