loki-mode 7.40.0 → 7.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/completion-council.sh +14 -2
- package/autonomy/council-v2.sh +10 -1
- package/autonomy/grill.sh +9 -1
- package/autonomy/lib/claude-flags.sh +269 -0
- package/autonomy/lib/voter-agents.sh +7 -1
- package/autonomy/run.sh +75 -6
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +15 -1
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/skills/quality-gates.md +33 -0
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, 11 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 v7.
|
|
6
|
+
# Loki Mode v7.41.0
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -398,4 +398,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
398
398
|
|
|
399
399
|
---
|
|
400
400
|
|
|
401
|
-
**v7.
|
|
401
|
+
**v7.41.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
7.
|
|
1
|
+
7.41.0
|
|
@@ -1775,7 +1775,15 @@ ISSUES: CRITICAL:description (optional, one per line per issue)"
|
|
|
1775
1775
|
if type loki_review_guard_enabled >/dev/null 2>&1 && loki_review_guard_enabled; then
|
|
1776
1776
|
_cm_argv+=("--disallowedTools" "$(loki_review_guard_denylist)")
|
|
1777
1777
|
fi
|
|
1778
|
-
|
|
1778
|
+
# caveman HARD-SUPPRESS (parsed output): this council vote is
|
|
1779
|
+
# parsed for "VOTE: APPROVE|REJECT|CANNOT_VALIDATE". A globally-
|
|
1780
|
+
# active caveman would compress/reword that line and silently flip
|
|
1781
|
+
# the vote to the default REJECT, corrupting completion detection.
|
|
1782
|
+
# Disable caveman UNCONDITIONALLY with CAVEMAN_DEFAULT_MODE=off.
|
|
1783
|
+
# Set inline (not via a helper) so the carve-out holds even when
|
|
1784
|
+
# this file is sourced standalone and the helpers are out of scope.
|
|
1785
|
+
# Inlined on `claude` only (does not cross the pipe). No-op absent.
|
|
1786
|
+
verdict=$(echo "$prompt" | env CAVEMAN_DEFAULT_MODE=off claude "${_cm_argv[@]}" -p 2>/dev/null | tail -20)
|
|
1779
1787
|
fi
|
|
1780
1788
|
;;
|
|
1781
1789
|
codex)
|
|
@@ -1870,7 +1878,11 @@ REASON: your reasoning"
|
|
|
1870
1878
|
if type loki_review_guard_enabled >/dev/null 2>&1 && loki_review_guard_enabled; then
|
|
1871
1879
|
_co_argv+=("--disallowedTools" "$(loki_review_guard_denylist)")
|
|
1872
1880
|
fi
|
|
1873
|
-
|
|
1881
|
+
# caveman HARD-SUPPRESS (parsed output): the devil's-advocate
|
|
1882
|
+
# (contrarian) vote is parsed for "VOTE:". Disable caveman
|
|
1883
|
+
# unconditionally so compression cannot flip the contrarian vote.
|
|
1884
|
+
# Inlined on `claude` only (does not cross the pipe). No-op absent.
|
|
1885
|
+
verdict=$(echo "$prompt" | env CAVEMAN_DEFAULT_MODE=off claude "${_co_argv[@]}" -p 2>/dev/null | tail -20)
|
|
1874
1886
|
fi
|
|
1875
1887
|
;;
|
|
1876
1888
|
codex)
|
package/autonomy/council-v2.sh
CHANGED
|
@@ -276,7 +276,16 @@ Respond ONLY with a valid JSON object. No markdown fencing."
|
|
|
276
276
|
if type loki_review_guard_enabled >/dev/null 2>&1 && loki_review_guard_enabled; then
|
|
277
277
|
_c2_argv+=("--disallowedTools" "$(loki_review_guard_denylist)")
|
|
278
278
|
fi
|
|
279
|
-
|
|
279
|
+
# caveman HARD-SUPPRESS (parsed output, v7.41.0): this reviewer
|
|
280
|
+
# verdict is captured and parsed for the JSON "verdict" field. A
|
|
281
|
+
# globally-active caveman would compress/reword that JSON and
|
|
282
|
+
# silently flip the verdict to the REJECT fallback. The tree-wide
|
|
283
|
+
# default-off export in claude-flags.sh already covers this (the
|
|
284
|
+
# whole subprocess tree inherits CAVEMAN_DEFAULT_MODE=off); the
|
|
285
|
+
# inline prefix here is belt-and-suspenders so the carve-out is
|
|
286
|
+
# self-documenting and robust to sourcing order. No-op when caveman
|
|
287
|
+
# is absent.
|
|
288
|
+
result=$(echo "$full_prompt" | CAVEMAN_DEFAULT_MODE=off claude "${_c2_argv[@]}" -p 2>/dev/null || echo '{"verdict":"REJECT","reasoning":"review execution failed","issues":[]}')
|
|
280
289
|
else
|
|
281
290
|
result='{"verdict":"REJECT","reasoning":"reviewer CLI unavailable","issues":[]}'
|
|
282
291
|
fi
|
package/autonomy/grill.sh
CHANGED
|
@@ -204,8 +204,16 @@ grill_invoke_provider() {
|
|
|
204
204
|
if type loki_review_guard_enabled >/dev/null 2>&1 && loki_review_guard_enabled; then
|
|
205
205
|
_gr_argv+=("--disallowedTools" "$(loki_review_guard_denylist)")
|
|
206
206
|
fi
|
|
207
|
+
# caveman HARD-SUPPRESS (parsed output, v7.41.0): the grill output is
|
|
208
|
+
# parsed downstream by loki-grill (and written to report.md as the
|
|
209
|
+
# hardest spec questions). Treat it as parsed: a globally-active
|
|
210
|
+
# caveman would compress/reword the questions. The tree-wide default-off
|
|
211
|
+
# export in claude-flags.sh (sourced at grill.sh:45) already covers
|
|
212
|
+
# this; the inline `env` prefix is belt-and-suspenders. `env` is used
|
|
213
|
+
# (not a bare VAR=val prefix) because the call goes through
|
|
214
|
+
# _grill_with_timeout, where the first token is exec'd as the command.
|
|
207
215
|
out="$(printf '%s' "$prompt" \
|
|
208
|
-
| _grill_with_timeout "${LOKI_GRILL_TIMEOUT:-180}" claude "${_gr_argv[@]}" -p - 2>/dev/null)"
|
|
216
|
+
| _grill_with_timeout "${LOKI_GRILL_TIMEOUT:-180}" env CAVEMAN_DEFAULT_MODE=off claude "${_gr_argv[@]}" -p - 2>/dev/null)"
|
|
209
217
|
if [ -z "$out" ]; then
|
|
210
218
|
_grill_err "provider returned no output (timeout or invocation error)"
|
|
211
219
|
return $GRILL_EXIT_ERROR
|
|
@@ -482,6 +482,275 @@ loki_workflows_enabled() {
|
|
|
482
482
|
[ "${LOKI_USE_CLAUDE_WORKFLOWS:-0}" = "1" ]
|
|
483
483
|
}
|
|
484
484
|
|
|
485
|
+
# ---------- v7.x caveman output-token compressor gates ----------
|
|
486
|
+
# caveman (https://github.com/JuliusBrussee/caveman, MIT, vendor-less pin) is a
|
|
487
|
+
# Claude Code SKILL + SessionStart hook that instructs the model to compress its
|
|
488
|
+
# OUTPUT TOKENS only (prose style: lite / full / ultra / wenyan), keeping all
|
|
489
|
+
# technical substance. It wraps NO API, needs NO key, has NO network of its own.
|
|
490
|
+
# Once installed it activates GLOBALLY in Claude Code via a SessionStart hook
|
|
491
|
+
# that reads getDefaultMode() (env CAVEMAN_DEFAULT_MODE > repo .caveman config >
|
|
492
|
+
# user config > "full") and, unless the mode is "off", injects its ruleset.
|
|
493
|
+
#
|
|
494
|
+
# THE MOAT RISK (central, why this is wired the way it is): Loki's trust gates
|
|
495
|
+
# parse EXACT model prose -- council "VOTE: APPROVE|REJECT|CANNOT_VALIDATE", code
|
|
496
|
+
# review "^VERDICT:", the legacy completion-promise grep, the evidence-gate
|
|
497
|
+
# sentinels. A globally-active caveman would compress those subcall outputs and
|
|
498
|
+
# silently flip a verdict to the default (REJECT / not-complete), corrupting the
|
|
499
|
+
# loop. This is the same failure class as the --bare OAuth footgun documented at
|
|
500
|
+
# claude-flags.sh:152-161.
|
|
501
|
+
#
|
|
502
|
+
# THE DESIGN (off by construction, not by convention):
|
|
503
|
+
# - ACTIVATE compression only on FREE-FORM generation (main RARV dev loop +
|
|
504
|
+
# read-only codebase-analysis): inline `CAVEMAN_DEFAULT_MODE=<level> claude`.
|
|
505
|
+
# - HARD-SUPPRESS on EVERY parsed-output subcall (council vote, ^VERDICT:
|
|
506
|
+
# review, adversarial probe, conflict-merge, USAGE regen): inline
|
|
507
|
+
# `CAVEMAN_DEFAULT_MODE=off claude`. The activate hook then deletes its flag
|
|
508
|
+
# and emits nothing (verified: `CAVEMAN_DEFAULT_MODE=off node
|
|
509
|
+
# caveman-activate.js` prints "OK" with no ruleset).
|
|
510
|
+
#
|
|
511
|
+
# Suppression is UNCONDITIONAL and UNGATED (see loki_caveman_suppress_env): it is
|
|
512
|
+
# a harmless no-op env value when caveman is absent and the essential carve-out
|
|
513
|
+
# when caveman is globally present (surface b, or a user's own install) even with
|
|
514
|
+
# LOKI_CAVEMAN=0. NEVER gate suppression on supported/enabled -- that would leave
|
|
515
|
+
# the trust gates unprotected exactly when a user has caveman on but Loki off.
|
|
516
|
+
#
|
|
517
|
+
# Disclosure (honest, no fabricated figures): caveman compresses OUTPUT tokens
|
|
518
|
+
# only, not input/thinking; savings are real but bounded. There is no price API,
|
|
519
|
+
# so we disclose the savings CLASS, never a dollar amount (same posture as the
|
|
520
|
+
# ultrareview/workflows gates).
|
|
521
|
+
|
|
522
|
+
# Version pin (vendor-less). Upgrade by bumping this. The upstream installer pins
|
|
523
|
+
# its hook downloads to PINNED_REF = CAVEMAN_REF || 'v1.9.0' (a git tag), and the
|
|
524
|
+
# curl|bash path delegates to `npx -y github:JuliusBrussee/caveman#<ref>`. We
|
|
525
|
+
# default to 1.9.0 and derive the `v`-prefixed tag in the bootstrap helper.
|
|
526
|
+
LOKI_CAVEMAN_VERSION="${LOKI_CAVEMAN_VERSION:-1.9.0}"
|
|
527
|
+
|
|
528
|
+
# The compression level for free-form activation. Maps directly to caveman's
|
|
529
|
+
# CAVEMAN_DEFAULT_MODE values: lite | full | ultra | wenyan | wenyan-lite |
|
|
530
|
+
# wenyan-full | wenyan-ultra. Default "full" (the founder-locked global default).
|
|
531
|
+
# Never "off" here -- "off" is the suppression value, not an activation level.
|
|
532
|
+
LOKI_CAVEMAN_LEVEL="${LOKI_CAVEMAN_LEVEL:-full}"
|
|
533
|
+
|
|
534
|
+
# ---------- DEFAULT-SUPPRESS: off by construction, tree-wide ----------
|
|
535
|
+
# THE MOAT GUARANTEE (v7.41.0 council fix): instead of hand-enumerating every
|
|
536
|
+
# parsed-output trust-gate subcall and remembering to prefix each with
|
|
537
|
+
# CAVEMAN_DEFAULT_MODE=off (a missed site silently corrupts a verdict -- caveman
|
|
538
|
+
# exits 0 with mangled prose and the `|| REJECT` fallback never fires), we flip
|
|
539
|
+
# the ENTIRE process tree to suppressed at the one module every tree sources.
|
|
540
|
+
#
|
|
541
|
+
# claude-flags.sh is sourced by EVERY tree that can spawn a parsed claude
|
|
542
|
+
# subcall: the run.sh orchestrator (via providers/claude.sh), grill.sh (standalone
|
|
543
|
+
# `loki grill`), lib/voter-agents.sh (Phase C agent-dispatch voters), and the
|
|
544
|
+
# loki standalone review/workflows commands (on-demand). council-v2.sh carries no
|
|
545
|
+
# source of its own but only ever runs inside completion-council.sh, which is in
|
|
546
|
+
# the run.sh tree, so it inherits this export too. Exporting off HERE makes the
|
|
547
|
+
# whole spawned subprocess tree inherit suppression -- caveman's SessionStart
|
|
548
|
+
# hook reads process.env CAVEMAN_DEFAULT_MODE -- closing council-v2.sh,
|
|
549
|
+
# voter-agents.sh, grill.sh, every existing parsed subcall, and any FUTURE one by
|
|
550
|
+
# construction. ACTIVATION on the handful of free-form generation sites overrides
|
|
551
|
+
# this per-invocation (CAVEMAN_DEFAULT_MODE=<level> claude ...).
|
|
552
|
+
#
|
|
553
|
+
# Capture the user's pre-existing global CAVEMAN_DEFAULT_MODE BEFORE we clobber
|
|
554
|
+
# it, so the activation path can respect (never RAISE) a user's lower level (see
|
|
555
|
+
# loki_caveman_activate_env). Guarded on UNSET (not empty): a child process that
|
|
556
|
+
# inherits our exported LOKI_CAVEMAN_USER_MODE="" (user had no global mode) and
|
|
557
|
+
# re-sources this file must NOT recapture the now-exported CAVEMAN_DEFAULT_MODE=off
|
|
558
|
+
# as the user mode. ${var+x} is empty only when var is genuinely unset, so the
|
|
559
|
+
# capture runs exactly once across the whole process tree, never recapturing "off".
|
|
560
|
+
if [ -z "${LOKI_CAVEMAN_USER_MODE+x}" ]; then
|
|
561
|
+
LOKI_CAVEMAN_USER_MODE="${CAVEMAN_DEFAULT_MODE:-}"
|
|
562
|
+
fi
|
|
563
|
+
export LOKI_CAVEMAN_USER_MODE
|
|
564
|
+
export CAVEMAN_DEFAULT_MODE=off
|
|
565
|
+
|
|
566
|
+
# Rank a caveman mode by compression aggressiveness for the no-raise comparison.
|
|
567
|
+
# Higher number = more aggressive (drops more nuance). "off" is the floor; unknown
|
|
568
|
+
# or empty modes rank as -1 (treated as "no opinion", so they never win a min()).
|
|
569
|
+
# The wenyan-* variants mirror their plain counterparts' aggressiveness.
|
|
570
|
+
_loki_caveman_level_rank() {
|
|
571
|
+
case "${1:-}" in
|
|
572
|
+
off) printf '0' ;;
|
|
573
|
+
lite|wenyan-lite) printf '1' ;;
|
|
574
|
+
full|wenyan|wenyan-full) printf '2' ;;
|
|
575
|
+
ultra|wenyan-ultra) printf '3' ;;
|
|
576
|
+
*) printf '%s' '-1' ;;
|
|
577
|
+
esac
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
# Caveman config dir resolution mirrors caveman-config.js getConfigDir(): honors
|
|
581
|
+
# CLAUDE_CONFIG_DIR for the flag file location used to detect an existing install.
|
|
582
|
+
_loki_caveman_claude_dir() {
|
|
583
|
+
printf '%s' "${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
# True (0) when caveman appears installed: its SessionStart hook file exists in
|
|
587
|
+
# the resolved Claude config dir. Best-effort, read-only. We check the hook the
|
|
588
|
+
# upstream installer writes to ~/.claude/hooks/caveman-activate.js (standalone)
|
|
589
|
+
# OR a plugin install marker. Either presence means activation will fire.
|
|
590
|
+
_loki_caveman_installed() {
|
|
591
|
+
local dir
|
|
592
|
+
dir="$(_loki_caveman_claude_dir)"
|
|
593
|
+
[ -f "$dir/hooks/caveman-activate.js" ] && return 0
|
|
594
|
+
# Plugin install: the activate hook lives under a plugin root; the flag file
|
|
595
|
+
# path is stable. Treat a prior-session flag file as a weaker install signal.
|
|
596
|
+
[ -f "$dir/.caveman-active" ] && return 0
|
|
597
|
+
return 1
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
# Capability gate: can caveman compression be USED on this run? Provider is
|
|
601
|
+
# Claude AND the claude CLI is present AND caveman is installed-or-bootstrappable
|
|
602
|
+
# AND it is not disabled by the LOKI_CAVEMAN knob. Returns 0 when usable, 1
|
|
603
|
+
# otherwise (callers emit an honest message + degrade to an uncompressed run).
|
|
604
|
+
# Mirrors loki_workflows_supported's shape (provider + CLI + not-disabled).
|
|
605
|
+
loki_caveman_supported() {
|
|
606
|
+
# Provider must be Claude (Tier 1). caveman is Claude-Code-only.
|
|
607
|
+
[ "${LOKI_PROVIDER:-claude}" = "claude" ] || return 1
|
|
608
|
+
command -v claude >/dev/null 2>&1 || return 1
|
|
609
|
+
# Opt-out knob also suppresses the capability (no activation when off).
|
|
610
|
+
[ "${LOKI_CAVEMAN:-1}" = "0" ] && return 1
|
|
611
|
+
# Installed now, OR bootstrappable (node + npx present so the pin can install
|
|
612
|
+
# on demand). Either way activation can take effect this run or the next.
|
|
613
|
+
if _loki_caveman_installed; then
|
|
614
|
+
return 0
|
|
615
|
+
fi
|
|
616
|
+
command -v node >/dev/null 2>&1 && command -v npx >/dev/null 2>&1 && return 0
|
|
617
|
+
return 1
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
# Activation knob: is caveman compression ENABLED for free-form subcalls?
|
|
621
|
+
# DEFAULT ON (LOKI_CAVEMAN unset or 1). Opt out with LOKI_CAVEMAN=0.
|
|
622
|
+
#
|
|
623
|
+
# CROSS-COUPLING GUARD (moat safety): when LOKI_LEGACY_COMPLETION_MATCH=true the
|
|
624
|
+
# runner detects completion by grepping the MAIN-loop prose for the completion
|
|
625
|
+
# promise (run.sh:9641). Compressing the main loop would mangle that prose and
|
|
626
|
+
# break the legacy detector, so caveman activation is DISABLED whenever the
|
|
627
|
+
# legacy prose-match path is in use. The default completion path (the
|
|
628
|
+
# loki_complete_task MCP tool / COMPLETION_REQUESTED signal file) is immune to
|
|
629
|
+
# compression, so the default config keeps caveman on.
|
|
630
|
+
loki_caveman_enabled() {
|
|
631
|
+
[ "${LOKI_CAVEMAN:-1}" = "0" ] && return 1
|
|
632
|
+
[ "${LOKI_LEGACY_COMPLETION_MATCH:-false}" = "true" ] && return 1
|
|
633
|
+
return 0
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
# The activation env VALUE for a free-form subcall: the configured level, or
|
|
637
|
+
# empty when activation is not warranted (caveman unsupported or disabled). The
|
|
638
|
+
# caller inlines it as a per-invocation env prefix (NEVER `export` -- a persisted
|
|
639
|
+
# export would bleed into later parsed subcalls and defeat the carve-out):
|
|
640
|
+
# _cm_lvl="$(loki_caveman_activate_env)"
|
|
641
|
+
# if [ -n "$_cm_lvl" ]; then
|
|
642
|
+
# CAVEMAN_DEFAULT_MODE="$_cm_lvl" claude ... # free-form only
|
|
643
|
+
# else
|
|
644
|
+
# claude ...
|
|
645
|
+
# fi
|
|
646
|
+
#
|
|
647
|
+
# NO-RAISE (v7.41.0 R2 finding 4): the level returned is the configured Loki
|
|
648
|
+
# level, EXCEPT we never silently RAISE a user who set a LOWER global caveman
|
|
649
|
+
# level. If the user globally chose "lite" (less aggressive, preserves more
|
|
650
|
+
# nuance) we honor "lite" rather than forcing "full" on their free-form output.
|
|
651
|
+
# We only ever lower toward the user's preference, never above it; the activation
|
|
652
|
+
# level itself is the conservative-for-accuracy ceiling. The user's global mode is
|
|
653
|
+
# captured at source time into LOKI_CAVEMAN_USER_MODE before the default-off
|
|
654
|
+
# export clobbers CAVEMAN_DEFAULT_MODE. Unknown / empty user modes (rank -1) are
|
|
655
|
+
# ignored so a malformed value can never accidentally suppress activation.
|
|
656
|
+
loki_caveman_activate_env() {
|
|
657
|
+
loki_caveman_supported || return 0
|
|
658
|
+
loki_caveman_enabled || return 0
|
|
659
|
+
local level="${LOKI_CAVEMAN_LEVEL:-full}"
|
|
660
|
+
# Respect (never exceed) a user's explicitly-lower global level. A user who
|
|
661
|
+
# globally set CAVEMAN_DEFAULT_MODE=off opted OUT of compression entirely;
|
|
662
|
+
# honor that by activating nothing (empty -> bare claude invocation).
|
|
663
|
+
local user_mode="${LOKI_CAVEMAN_USER_MODE:-}"
|
|
664
|
+
if [ "$user_mode" = "off" ]; then
|
|
665
|
+
return 0
|
|
666
|
+
fi
|
|
667
|
+
if [ -n "$user_mode" ]; then
|
|
668
|
+
local user_rank level_rank
|
|
669
|
+
user_rank="$(_loki_caveman_level_rank "$user_mode")"
|
|
670
|
+
level_rank="$(_loki_caveman_level_rank "$level")"
|
|
671
|
+
# Only defer to the user when their mode is a recognized, lower level.
|
|
672
|
+
if [ "$user_rank" -ge 0 ] && [ "$level_rank" -ge 0 ] && [ "$user_rank" -lt "$level_rank" ]; then
|
|
673
|
+
level="$user_mode"
|
|
674
|
+
fi
|
|
675
|
+
fi
|
|
676
|
+
printf '%s' "$level"
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
# The suppression env VALUE for a parsed-output subcall: ALWAYS "off",
|
|
680
|
+
# UNCONDITIONALLY. Not gated on supported/enabled (see the design note above):
|
|
681
|
+
# it must hard-disable caveman on a trust-gate subcall even when a user has
|
|
682
|
+
# caveman globally on but LOKI_CAVEMAN=0, and it is a harmless no-op env value
|
|
683
|
+
# when caveman is absent. Every parsed-output call site uses this ONE helper so
|
|
684
|
+
# the carve-out is uniform:
|
|
685
|
+
# CAVEMAN_DEFAULT_MODE="$(loki_caveman_suppress_env)" claude ...
|
|
686
|
+
loki_caveman_suppress_env() {
|
|
687
|
+
printf '%s' "off"
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
# Idempotent on-demand bootstrap of caveman at the pinned version. Best-effort:
|
|
691
|
+
# installs once per machine, caches a marker under .loki/ so repeat runs are a
|
|
692
|
+
# no-op, degrades cleanly (run proceeds UNCOMPRESSED) with an honest stderr line
|
|
693
|
+
# if anything is missing or the upstream installer is unreachable. NEVER blocks
|
|
694
|
+
# or fails the run. Returns 0 if caveman is (now) installed, 1 on clean degrade.
|
|
695
|
+
#
|
|
696
|
+
# Opt out with LOKI_CAVEMAN_AUTO_BOOTSTRAP=0. Only attempts when provider==claude
|
|
697
|
+
# and the LOKI_CAVEMAN knob is on.
|
|
698
|
+
#
|
|
699
|
+
# GLOBAL SIDE EFFECT (disclosed): caveman installs GLOBALLY -- the upstream
|
|
700
|
+
# installer adds a SessionStart hook to ~/.claude/settings.json (or
|
|
701
|
+
# $CLAUDE_CONFIG_DIR) that affects EVERY Claude Code session on this machine, not
|
|
702
|
+
# only Loki runs. This is caveman's only install mode. The bootstrap therefore
|
|
703
|
+
# runs the upstream installer exactly as a user's own `curl|bash` would; we do
|
|
704
|
+
# not author or vendor any caveman file. The one-time stderr line below names
|
|
705
|
+
# this so the operator is never surprised.
|
|
706
|
+
#
|
|
707
|
+
# HARDENING: the npx call is forced non-interactive (--non-interactive, plus
|
|
708
|
+
# </dev/null so no stdin read can ever block) and time-bounded (timeout when
|
|
709
|
+
# available) so a stalled network or an unexpected prompt can never hang a user's
|
|
710
|
+
# first `loki start`. caveman's installer is already auto-non-interactive without
|
|
711
|
+
# a TTY, but we belt-and-suspenders it.
|
|
712
|
+
loki_caveman_bootstrap() {
|
|
713
|
+
[ "${LOKI_CAVEMAN:-1}" = "0" ] && return 1
|
|
714
|
+
[ "${LOKI_CAVEMAN_AUTO_BOOTSTRAP:-1}" = "0" ] && return 1
|
|
715
|
+
[ "${LOKI_PROVIDER:-claude}" = "claude" ] || return 1
|
|
716
|
+
# Already installed -> nothing to do.
|
|
717
|
+
if _loki_caveman_installed; then
|
|
718
|
+
return 0
|
|
719
|
+
fi
|
|
720
|
+
local ver="${LOKI_CAVEMAN_VERSION:-1.9.0}"
|
|
721
|
+
local marker_dir=".loki/state"
|
|
722
|
+
local marker="$marker_dir/caveman-bootstrap-${ver}.done"
|
|
723
|
+
# Cached attempt marker: do not re-attempt a failed install over and over
|
|
724
|
+
# within the same project tree (idempotent one-shot per pinned version).
|
|
725
|
+
if [ -f "$marker" ]; then
|
|
726
|
+
_loki_caveman_installed && return 0 || return 1
|
|
727
|
+
fi
|
|
728
|
+
if ! command -v node >/dev/null 2>&1 || ! command -v npx >/dev/null 2>&1; then
|
|
729
|
+
printf '%s\n' "[caveman] node>=18 + npx required to bootstrap; skipping (run proceeds uncompressed). Install Node or set LOKI_CAVEMAN=0 to silence." >&2
|
|
730
|
+
mkdir -p "$marker_dir" 2>/dev/null && : > "$marker" 2>/dev/null || true
|
|
731
|
+
return 1
|
|
732
|
+
fi
|
|
733
|
+
printf '%s\n' "[caveman] bootstrapping output-token compressor v${ver} (one-time, pinned). NOTE: caveman installs GLOBALLY (a Claude Code SessionStart hook in ~/.claude affecting every Claude Code session). Loki applies it only to free-form generation, NEVER to trust-gate subcalls. Opt out: LOKI_CAVEMAN=0." >&2
|
|
734
|
+
# Pin via the git tag (v-prefixed) on the npx ref AND CAVEMAN_REF so the
|
|
735
|
+
# downloaded hooks match the pinned release. Default install (no --all) wires
|
|
736
|
+
# the Claude Code hook for the detected `claude` CLI. A timeout backstops a
|
|
737
|
+
# network stall; </dev/null guarantees no interactive stdin read blocks.
|
|
738
|
+
local _cm_runner="npx"
|
|
739
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
740
|
+
_cm_runner="timeout 120 npx"
|
|
741
|
+
fi
|
|
742
|
+
if CAVEMAN_REF="v${ver}" $_cm_runner -y "github:JuliusBrussee/caveman#v${ver}" -- --non-interactive >/dev/null 2>&1 </dev/null; then
|
|
743
|
+
mkdir -p "$marker_dir" 2>/dev/null && : > "$marker" 2>/dev/null || true
|
|
744
|
+
if _loki_caveman_installed; then
|
|
745
|
+
printf '%s\n' "[caveman] installed v${ver}." >&2
|
|
746
|
+
return 0
|
|
747
|
+
fi
|
|
748
|
+
fi
|
|
749
|
+
printf '%s\n' "[caveman] bootstrap unavailable (upstream unreachable, timed out, or install failed); run proceeds uncompressed." >&2
|
|
750
|
+
mkdir -p "$marker_dir" 2>/dev/null && : > "$marker" 2>/dev/null || true
|
|
751
|
+
return 1
|
|
752
|
+
}
|
|
753
|
+
|
|
485
754
|
# ---------------------------------------------------------------------------
|
|
486
755
|
# Session-continuity Phase 2 (GitHub #165) -- LOKI_RESUME_SESSION recovery resume
|
|
487
756
|
#
|
|
@@ -250,7 +250,13 @@ loki_council_dispatch_agents() {
|
|
|
250
250
|
local rc=0
|
|
251
251
|
local stderr_log="$COUNCIL_STATE_DIR/votes/dispatch-stderr-${iteration}.log"
|
|
252
252
|
mkdir -p "$(dirname "$stderr_log")" 2>/dev/null || true
|
|
253
|
-
|
|
253
|
+
# caveman HARD-SUPPRESS (parsed output, v7.41.0): the response is parsed for
|
|
254
|
+
# findings[].vote against the JSON Schema. A globally-active caveman would
|
|
255
|
+
# compress/reword it and break the schema match or flip a vote. The tree-wide
|
|
256
|
+
# default-off export in claude-flags.sh (sourced above) already covers this;
|
|
257
|
+
# the inline prefix is belt-and-suspenders, self-documenting, and a no-op when
|
|
258
|
+
# caveman is absent.
|
|
259
|
+
response=$(CAVEMAN_DEFAULT_MODE=off claude --dangerously-skip-permissions \
|
|
254
260
|
-p "$prompt" \
|
|
255
261
|
--agents "$agents_json" \
|
|
256
262
|
--json-schema "$schema_path" 2>"$stderr_log") || rc=$?
|
package/autonomy/run.sh
CHANGED
|
@@ -3050,9 +3050,24 @@ spawn_worktree_session() {
|
|
|
3050
3050
|
# Provider-specific invocation for parallel sessions
|
|
3051
3051
|
case "${PROVIDER_NAME:-claude}" in
|
|
3052
3052
|
claude)
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3053
|
+
# caveman ACTIVATION (free-form): a parallel worktree dev stream
|
|
3054
|
+
# is free-form generation; its output goes to a log, not a parsed
|
|
3055
|
+
# sentinel. Activate compression at the configured level when
|
|
3056
|
+
# warranted (empty -> bare invocation, byte-identical to before).
|
|
3057
|
+
# Type-guarded; inlined per-invocation (not exported).
|
|
3058
|
+
local _loki_wt_cm=""
|
|
3059
|
+
if type loki_caveman_activate_env >/dev/null 2>&1; then
|
|
3060
|
+
_loki_wt_cm="$(loki_caveman_activate_env)"
|
|
3061
|
+
fi
|
|
3062
|
+
if [ -n "$_loki_wt_cm" ]; then
|
|
3063
|
+
CAVEMAN_DEFAULT_MODE="$_loki_wt_cm" claude --dangerously-skip-permissions \
|
|
3064
|
+
-p "Loki Mode: $task_prompt. Read .loki/CONTINUITY.md for context." \
|
|
3065
|
+
>> "$log_file" 2>&1 || _wt_exit=$?
|
|
3066
|
+
else
|
|
3067
|
+
claude --dangerously-skip-permissions \
|
|
3068
|
+
-p "Loki Mode: $task_prompt. Read .loki/CONTINUITY.md for context." \
|
|
3069
|
+
>> "$log_file" 2>&1 || _wt_exit=$?
|
|
3070
|
+
fi
|
|
3056
3071
|
;;
|
|
3057
3072
|
codex)
|
|
3058
3073
|
codex exec --full-auto --skip-git-repo-check \
|
|
@@ -3264,7 +3279,11 @@ Output ONLY the resolved file content with no conflict markers. No explanations.
|
|
|
3264
3279
|
if type loki_subcall_bare_enabled >/dev/null 2>&1 && loki_subcall_bare_enabled; then
|
|
3265
3280
|
_cr_argv+=("--bare")
|
|
3266
3281
|
fi
|
|
3267
|
-
|
|
3282
|
+
# caveman HARD-SUPPRESS (parsed output): the output is captured as
|
|
3283
|
+
# the EXACT resolved file content (the shell writes it verbatim).
|
|
3284
|
+
# Compressing prose into the merged source would corrupt the file,
|
|
3285
|
+
# so disable caveman unconditionally here. No-op when absent.
|
|
3286
|
+
resolution=$(CAVEMAN_DEFAULT_MODE=off claude "${_cr_argv[@]}" -p "$conflict_prompt" --output-format text 2>/dev/null)
|
|
3268
3287
|
;;
|
|
3269
3288
|
codex)
|
|
3270
3289
|
resolution=$(codex exec --full-auto --skip-git-repo-check "$conflict_prompt" 2>/dev/null)
|
|
@@ -7912,6 +7931,15 @@ BUILD_PROMPT
|
|
|
7912
7931
|
if type loki_review_allowlist_enabled >/dev/null 2>&1 && loki_review_allowlist_enabled; then
|
|
7913
7932
|
_rv_argv+=("--allowedTools" "$(loki_review_allowlist)")
|
|
7914
7933
|
fi
|
|
7934
|
+
# caveman HARD-SUPPRESS (parsed output): this is a trust-gate
|
|
7935
|
+
# subcall whose output is parsed for "^VERDICT:" + findings. A
|
|
7936
|
+
# globally-active caveman would compress/reword that line and
|
|
7937
|
+
# silently flip the verdict, so we UNCONDITIONALLY disable
|
|
7938
|
+
# caveman here with CAVEMAN_DEFAULT_MODE=off (the activate hook
|
|
7939
|
+
# then deletes its flag and emits nothing). Set inline, not via
|
|
7940
|
+
# the helper, so the carve-out holds even when the helper is
|
|
7941
|
+
# out of scope. No-op when caveman is absent.
|
|
7942
|
+
CAVEMAN_DEFAULT_MODE=off \
|
|
7915
7943
|
claude "${_rv_argv[@]}" -p "$prompt_text" \
|
|
7916
7944
|
--output-format text > "$review_output" 2>/dev/null
|
|
7917
7945
|
;;
|
|
@@ -8151,6 +8179,11 @@ ADVERSARIAL_EOF
|
|
|
8151
8179
|
if type loki_review_allowlist_enabled >/dev/null 2>&1 && loki_review_allowlist_enabled; then
|
|
8152
8180
|
_adv_argv+=("--allowedTools" "$(loki_review_allowlist)")
|
|
8153
8181
|
fi
|
|
8182
|
+
# caveman HARD-SUPPRESS (parsed output): the adversarial probe's
|
|
8183
|
+
# output is parsed for findings/severity. Disable caveman
|
|
8184
|
+
# unconditionally (CAVEMAN_DEFAULT_MODE=off) so compression cannot
|
|
8185
|
+
# drop or reword a finding. No-op when caveman is absent.
|
|
8186
|
+
CAVEMAN_DEFAULT_MODE=off \
|
|
8154
8187
|
claude "${_adv_argv[@]}" -p "$adversarial_prompt" \
|
|
8155
8188
|
--output-format text > "$result_file" 2>/dev/null || true
|
|
8156
8189
|
fi
|
|
@@ -10188,9 +10221,14 @@ ${_commits}"
|
|
|
10188
10221
|
_ic_argv+=("--bare")
|
|
10189
10222
|
fi
|
|
10190
10223
|
_ic_argv+=("--model" "haiku")
|
|
10224
|
+
# caveman HARD-SUPPRESS (parsed output): the regen output is validated to be
|
|
10225
|
+
# Markdown (grep '^#') and written verbatim to USAGE.md. Compressed prose
|
|
10226
|
+
# would fail that check or produce caveman-style USAGE text, so disable
|
|
10227
|
+
# caveman unconditionally. Inlined on `claude` only (does not cross the pipe
|
|
10228
|
+
# to head). No-op when caveman is absent.
|
|
10191
10229
|
local _ic_out
|
|
10192
10230
|
_ic_out=$(printf '%s' "$_ic_prompt" \
|
|
10193
|
-
| timeout 60 claude "${_ic_argv[@]}" -p - 2>/dev/null \
|
|
10231
|
+
| timeout 60 env CAVEMAN_DEFAULT_MODE=off claude "${_ic_argv[@]}" -p - 2>/dev/null \
|
|
10194
10232
|
| head -200)
|
|
10195
10233
|
# Sanity check: response must look like Markdown (starts with # or ##).
|
|
10196
10234
|
if [ -z "$_ic_out" ] || ! printf '%s' "$_ic_out" | head -1 | grep -qE '^#'; then
|
|
@@ -13049,9 +13087,40 @@ except Exception as exc:
|
|
|
13049
13087
|
# result-cost file under the correct iteration index.
|
|
13050
13088
|
export LOKI_CURRENT_MODEL="$tier_param"
|
|
13051
13089
|
export LOKI_ITERATION="$ITERATION_COUNT"
|
|
13090
|
+
# caveman ACTIVATION (free-form): the main RARV dev loop is
|
|
13091
|
+
# free-form generation, so we ask caveman to compress its OUTPUT
|
|
13092
|
+
# tokens at the configured level. Inlined as a per-invocation env
|
|
13093
|
+
# prefix (NOT exported) so it applies ONLY to `claude` (and the
|
|
13094
|
+
# SessionStart hook it spawns inherits it) and never bleeds into
|
|
13095
|
+
# later parsed subcalls. Empty when caveman is unsupported /
|
|
13096
|
+
# disabled / the legacy completion-prose match is active, in which
|
|
13097
|
+
# case the invocation is byte-identical to before. Type-guarded so
|
|
13098
|
+
# an older runtime without the helper degrades cleanly.
|
|
13099
|
+
local _loki_cm_level=""
|
|
13100
|
+
if type loki_caveman_activate_env >/dev/null 2>&1; then
|
|
13101
|
+
_loki_cm_level="$(loki_caveman_activate_env)"
|
|
13102
|
+
fi
|
|
13103
|
+
# Best-effort one-time bootstrap when activation is warranted but
|
|
13104
|
+
# caveman is not yet installed (idempotent, non-blocking, clean
|
|
13105
|
+
# degrade). The level stays usable next run even if this run is
|
|
13106
|
+
# uncompressed.
|
|
13107
|
+
if [ -n "$_loki_cm_level" ] && type loki_caveman_bootstrap >/dev/null 2>&1; then
|
|
13108
|
+
loki_caveman_bootstrap || true
|
|
13109
|
+
fi
|
|
13110
|
+
# NOTE: an EMPTY CAVEMAN_DEFAULT_MODE is NOT inert -- caveman's
|
|
13111
|
+
# getDefaultMode() treats empty as unset and falls back to the
|
|
13112
|
+
# user's global default (often "full"). So when activation is not
|
|
13113
|
+
# warranted we must NOT set the var at all (the bare branch),
|
|
13114
|
+
# keeping the invocation byte-identical to pre-caveman behavior.
|
|
13052
13115
|
{ \
|
|
13116
|
+
if [ -n "$_loki_cm_level" ]; then
|
|
13117
|
+
CAVEMAN_DEFAULT_MODE="$_loki_cm_level" \
|
|
13118
|
+
claude "${_loki_claude_argv[@]}" -p "$prompt" \
|
|
13119
|
+
--output-format stream-json --verbose 2>&1
|
|
13120
|
+
else
|
|
13053
13121
|
claude "${_loki_claude_argv[@]}" -p "$prompt" \
|
|
13054
|
-
--output-format stream-json --verbose 2>&1
|
|
13122
|
+
--output-format stream-json --verbose 2>&1
|
|
13123
|
+
fi | \
|
|
13055
13124
|
tee -a "$log_file" "$agent_log" "$iter_output" | \
|
|
13056
13125
|
python3 -u -c '
|
|
13057
13126
|
import sys
|
package/dashboard/__init__.py
CHANGED
package/docs/INSTALLATION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The flagship product of [Autonomi](https://www.autonomi.dev/). Loki Mode is a spec-driven autonomous builder with a built-in trust layer that takes any spec to a deployed product and verifies completion with evidence (quality gates plus a completion council), not just a "done" claim. Complete installation instructions for all platforms and use cases.
|
|
4
4
|
|
|
5
|
-
**Version:** v7.
|
|
5
|
+
**Version:** v7.41.0
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -30,6 +30,20 @@ setting any flag to `0`.
|
|
|
30
30
|
in `loki status --json`).
|
|
31
31
|
- See `skills/quality-gates.md` for full schema and reachability notes.
|
|
32
32
|
|
|
33
|
+
### Output-token compressor (caveman, default-on, Claude-only)
|
|
34
|
+
Loki integrates [caveman](https://github.com/JuliusBrussee/caveman), an optional
|
|
35
|
+
Claude Code skill that compresses the model's OUTPUT tokens only (keeping all
|
|
36
|
+
technical substance). It activates on free-form generation (the main RARV dev
|
|
37
|
+
loop) and is HARD-SUPPRESSED on every trust-gate subcall (council votes, code
|
|
38
|
+
review verdict, evidence-related parses) so determinism is never affected.
|
|
39
|
+
- Claude-provider-only; runs are byte-identical on Codex / Cline / Aider.
|
|
40
|
+
- Default on; opt out with `LOKI_CAVEMAN=0`.
|
|
41
|
+
- Level: `LOKI_CAVEMAN_LEVEL` (default `full`; also `lite`, `ultra`, `wenyan*`).
|
|
42
|
+
- Pinned + vendor-less: `LOKI_CAVEMAN_VERSION` (default `1.9.0`); Loki bootstraps
|
|
43
|
+
the pinned version on demand (opt out `LOKI_CAVEMAN_AUTO_BOOTSTRAP=0`).
|
|
44
|
+
- Savings are output-token-only and bounded; Loki never quotes a dollar figure.
|
|
45
|
+
- See `skills/quality-gates.md` (Output-token compressor) for details.
|
|
46
|
+
|
|
33
47
|
### Earlier highlights still in scope
|
|
34
48
|
- Bash-to-Bun runtime migration in progress (see `UPGRADING.md`)
|
|
35
49
|
- Provider-agnostic runtime: Claude (full), Codex, Cline, Aider (no vendor lock-in)
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var n6=Object.defineProperty;var a6=($)=>$;function s6($,Q){this[$]=a6.bind(null,Q)}var h=($,Q)=>{for(var Z in Q)n6($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:s6.bind(Q,Z)})};var L=($,Q)=>()=>($&&(Q=$($=0)),Q);var K$=import.meta.require;var S1={};h(S1,{lokiDir:()=>P,homeLokiDir:()=>o$,findRepoRootForVersion:()=>d$,REPO_ROOT:()=>m});import{resolve as n,dirname as l$}from"path";import{fileURLToPath as t6}from"url";import{existsSync as P$}from"fs";import{homedir as r6}from"os";function i6(){let $=N1;for(let Q=0;Q<6;Q++){if(P$(n($,"VERSION"))&&P$(n($,"autonomy/run.sh")))return $;let Z=l$($);if(Z===$)break;$=Z}return n(N1,"..","..","..")}function d$($){let Q=$;for(let Z=0;Z<6;Z++){if(P$(n(Q,"VERSION"))&&P$(n(Q,"autonomy/run.sh")))return Q;let z=l$(Q);if(z===Q)break;Q=z}return n($,"..","..","..")}function P(){return process.env.LOKI_DIR??n(process.cwd(),".loki")}function o$(){return n(r6(),".loki")}var N1,m;var C=L(()=>{N1=l$(t6(import.meta.url));m=i6()});import{readFileSync as e6}from"fs";import{resolve as $Q,dirname as QQ}from"path";import{fileURLToPath as ZQ}from"url";function F$(){if($$!==null)return $$;let $="7.
|
|
2
|
+
var n6=Object.defineProperty;var a6=($)=>$;function s6($,Q){this[$]=a6.bind(null,Q)}var h=($,Q)=>{for(var Z in Q)n6($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:s6.bind(Q,Z)})};var L=($,Q)=>()=>($&&(Q=$($=0)),Q);var K$=import.meta.require;var S1={};h(S1,{lokiDir:()=>P,homeLokiDir:()=>o$,findRepoRootForVersion:()=>d$,REPO_ROOT:()=>m});import{resolve as n,dirname as l$}from"path";import{fileURLToPath as t6}from"url";import{existsSync as P$}from"fs";import{homedir as r6}from"os";function i6(){let $=N1;for(let Q=0;Q<6;Q++){if(P$(n($,"VERSION"))&&P$(n($,"autonomy/run.sh")))return $;let Z=l$($);if(Z===$)break;$=Z}return n(N1,"..","..","..")}function d$($){let Q=$;for(let Z=0;Z<6;Z++){if(P$(n(Q,"VERSION"))&&P$(n(Q,"autonomy/run.sh")))return Q;let z=l$(Q);if(z===Q)break;Q=z}return n($,"..","..","..")}function P(){return process.env.LOKI_DIR??n(process.cwd(),".loki")}function o$(){return n(r6(),".loki")}var N1,m;var C=L(()=>{N1=l$(t6(import.meta.url));m=i6()});import{readFileSync as e6}from"fs";import{resolve as $Q,dirname as QQ}from"path";import{fileURLToPath as ZQ}from"url";function F$(){if($$!==null)return $$;let $="7.41.0";if(typeof $==="string"&&$.length>0)return $$=$,$$;try{let Q=QQ(ZQ(import.meta.url)),Z=d$(Q);$$=e6($Q(Z,"VERSION"),"utf-8").trim()}catch{$$="unknown"}return $$}var $$=null;var n$=L(()=>{C()});var C1={};h(C1,{runOrThrow:()=>zQ,run:()=>j,commandVersion:()=>KQ,commandExists:()=>f,ShellError:()=>a$});async function j($,Q={}){let Z=Bun.spawn({cmd:[...$],stdout:"pipe",stderr:"pipe",env:Q.env?{...process.env,...Q.env}:process.env,cwd:Q.cwd}),z,X;if(Q.timeoutMs&&Q.timeoutMs>0)z=setTimeout(()=>{try{Z.kill("SIGTERM")}catch{}X=setTimeout(()=>{try{Z.kill("SIGKILL")}catch{}},2000)},Q.timeoutMs);try{let[W,K,U]=await Promise.all([new Response(Z.stdout).text(),new Response(Z.stderr).text(),Z.exited]);return{stdout:W,stderr:K,exitCode:U}}finally{if(z)clearTimeout(z);if(X)clearTimeout(X)}}async function zQ($,Q={}){let Z=await j($,Q);if(Z.exitCode!==0)throw new a$(`command failed (${Z.exitCode}): ${$.join(" ")}`,Z.exitCode,Z.stdout,Z.stderr);return Z}async function f($){let Q=XQ($),Z=await j(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function XQ($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function KQ($,Q="--version"){if(!await f($))return null;let z=await j([$,Q],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var a$;var d=L(()=>{a$=class a$ extends Error{message;exitCode;stdout;stderr;constructor($,Q,Z,z){super($);this.message=$;this.exitCode=Q;this.stdout=Z;this.stderr=z;this.name="ShellError"}}});function a($){return WQ?"":$}var WQ,T,S,I,TZ,w,R,y,q;var c=L(()=>{WQ=(process.env.NO_COLOR??"").length>0;T=a("\x1B[0;31m"),S=a("\x1B[0;32m"),I=a("\x1B[1;33m"),TZ=a("\x1B[0;34m"),w=a("\x1B[0;36m"),R=a("\x1B[1m"),y=a("\x1B[2m"),q=a("\x1B[0m")});import{existsSync as TQ}from"fs";async function Q$(){if(B$!==void 0)return B$;let $="/opt/homebrew/bin/python3.12";if(TQ($))return B$=$,$;let Q=await f("python3.12");if(Q)return B$=Q,Q;let Z=await f("python3");return B$=Z,Z}async function Z$($,Q={}){let Z=await Q$();if(!Z)return{stdout:"",stderr:"python3 not found",exitCode:127};return j([Z,"-c",$],Q)}var B$;var W$=L(()=>{d()});var t1={};h(t1,{runStatus:()=>gQ});import{existsSync as v,readFileSync as U$,readdirSync as l1,statSync as d1}from"fs";import{resolve as D,basename as xQ}from"path";import{homedir as NQ}from"os";async function DQ(){if(await f("jq"))return!0;return process.stdout.write(`${T}Error: jq is required but not installed.${q}
|
|
3
3
|
`),process.stdout.write(`Install with:
|
|
4
4
|
`),process.stdout.write(` brew install jq (macOS)
|
|
5
5
|
`),process.stdout.write(` apt install jq (Debian/Ubuntu)
|
|
@@ -789,4 +789,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
789
789
|
`),2}default:return process.stderr.write(`Unknown command: ${Q}
|
|
790
790
|
`),process.stderr.write(o6),2}}p1();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var ZZ=await QZ(Bun.argv.slice(2));process.exit(ZZ);
|
|
791
791
|
|
|
792
|
-
//# debugId=
|
|
792
|
+
//# debugId=02B592B55ABCECB264756E2164756E21
|
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loki-mode",
|
|
3
3
|
"mcpName": "io.github.asklokesh/loki-mode",
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.41.0",
|
|
5
5
|
"description": "Loki Mode by Autonomi. Autonomous spec-to-product system: takes a PRD, GitHub issue, OpenAPI/JSON/YAML, or one-line brief to a deployed app via the RARV-C closure loop with 11 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider).",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "loki-mode",
|
|
4
4
|
"displayName": "Loki Mode",
|
|
5
|
-
"version": "7.
|
|
5
|
+
"version": "7.41.0",
|
|
6
6
|
"description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 11 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Autonomi",
|
package/skills/quality-gates.md
CHANGED
|
@@ -128,6 +128,39 @@ LOKI_CODE_INDEX_AUTOREINDEX=1 # auto incremental re-index of the semantic
|
|
|
128
128
|
# Hybrid Codebase Search)
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
+
## Output-token compressor (caveman, default-on, Claude-only)
|
|
132
|
+
|
|
133
|
+
[caveman](https://github.com/JuliusBrussee/caveman) is a Claude Code skill that
|
|
134
|
+
instructs the model to compress its OUTPUT tokens only (prose style), keeping all
|
|
135
|
+
technical substance. Loki ACTIVATES it on free-form generation (the main RARV dev
|
|
136
|
+
loop) and HARD-SUPPRESSES it on every parsed-output trust-gate subcall (council
|
|
137
|
+
votes, the code-review `^VERDICT:`, the adversarial probe, the merge-conflict
|
|
138
|
+
resolver, the USAGE.md regen). The suppression is by construction (one shared
|
|
139
|
+
helper sets `CAVEMAN_DEFAULT_MODE=off` on every parsed call site), so compression
|
|
140
|
+
can NEVER flip a verdict or completion decision.
|
|
141
|
+
|
|
142
|
+
Claude-provider-only: on Codex / Cline / Aider the run is byte-identical to
|
|
143
|
+
before. Vendor-less: Loki ships no copy of caveman and bootstraps the pinned
|
|
144
|
+
version on demand (idempotent, cached under `.loki/`). Savings are real but
|
|
145
|
+
bounded (output tokens only); there is no price API, so Loki discloses the
|
|
146
|
+
savings CLASS, never a dollar figure.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
LOKI_CAVEMAN=0 # opt out (default on). Disables activation; the
|
|
150
|
+
# parsed-subcall suppression still runs (it is a
|
|
151
|
+
# harmless no-op when caveman is absent).
|
|
152
|
+
LOKI_CAVEMAN_LEVEL=full # compression level: lite | full (default) |
|
|
153
|
+
# ultra | wenyan | wenyan-lite|full|ultra
|
|
154
|
+
LOKI_CAVEMAN_VERSION=1.9.0 # pinned caveman version (upgrade by bumping)
|
|
155
|
+
LOKI_CAVEMAN_AUTO_BOOTSTRAP=0 # disable the on-demand pinned install
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Note: when `LOKI_LEGACY_COMPLETION_MATCH=true` (the legacy prose-grep completion
|
|
159
|
+
path), main-loop activation is automatically disabled so compression cannot
|
|
160
|
+
mangle the prose completion-promise. The default completion path (the
|
|
161
|
+
`loki_complete_task` MCP tool / completion signal file) is immune to compression
|
|
162
|
+
and keeps caveman on.
|
|
163
|
+
|
|
131
164
|
## Verified-completion evidence gate (v7.19.1, default-on)
|
|
132
165
|
|
|
133
166
|
The completion council will not accept a "done" claim without evidence. Before
|