loki-mode 6.81.1 → 6.83.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 +58 -0
- package/autonomy/run.sh +334 -44
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/mcp/__init__.py +1 -1
- package/mcp/requirements.txt +1 -0
- package/mcp/server.py +105 -0
- package/memory/managed_memory/__init__.py +113 -0
- package/memory/managed_memory/_beta.py +11 -0
- package/memory/managed_memory/client.py +210 -0
- package/memory/managed_memory/events.py +79 -0
- package/memory/managed_memory/fakes.py +120 -0
- package/memory/managed_memory/retrieve.py +347 -0
- package/memory/managed_memory/shadow_write.py +350 -0
- package/package.json +2 -2
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Multi-agent autonomous startup system. Triggers on "Loki Mode". Takes PRD to deployed product with minimal human intervention. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v6.
|
|
6
|
+
# Loki Mode v6.83.0
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -269,4 +269,4 @@ The following features are documented in skill modules but not yet fully automat
|
|
|
269
269
|
| Quality gates 3-reviewer system | Implemented (v5.35.0) | 5 specialist reviewers in `skills/quality-gates.md`; execution in run.sh |
|
|
270
270
|
| Benchmarks (HumanEval, SWE-bench) | Infrastructure only | Runner scripts and datasets exist in `benchmarks/`; no published results |
|
|
271
271
|
|
|
272
|
-
**v6.
|
|
272
|
+
**v6.83.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
6.
|
|
1
|
+
6.83.0
|
|
@@ -72,6 +72,38 @@ COUNCIL_DONE_SIGNALS=0
|
|
|
72
72
|
COUNCIL_TOTAL_DONE_SIGNALS=0
|
|
73
73
|
COUNCIL_LAST_DIFF_HASH=""
|
|
74
74
|
|
|
75
|
+
#===============================================================================
|
|
76
|
+
# v6.83.0 Phase 1: Managed Agents memory augmentation (opt-in).
|
|
77
|
+
#
|
|
78
|
+
# When LOKI_MANAGED_AGENTS=true AND LOKI_MANAGED_MEMORY=true, this function
|
|
79
|
+
# pulls up to 3 related prior verdicts from the Claude Managed Agents store
|
|
80
|
+
# and writes them to a file the council prompt-assembly step appends as
|
|
81
|
+
# "RELATED PRIOR VERDICTS". 5s hard timeout so a slow/unreachable API can
|
|
82
|
+
# never block the council. Silent no-op when the flags are off.
|
|
83
|
+
#===============================================================================
|
|
84
|
+
council_augment_from_managed_memory() {
|
|
85
|
+
if [ "${LOKI_MANAGED_AGENTS:-false}" != "true" ] || \
|
|
86
|
+
[ "${LOKI_MANAGED_MEMORY:-false}" != "true" ]; then
|
|
87
|
+
return 0
|
|
88
|
+
fi
|
|
89
|
+
local target_dir="${TARGET_DIR:-.}"
|
|
90
|
+
local project_dir="${PROJECT_DIR:-$(pwd)}"
|
|
91
|
+
local out_file="$target_dir/.loki/managed/council-augment.txt"
|
|
92
|
+
mkdir -p "$target_dir/.loki/managed" 2>/dev/null || true
|
|
93
|
+
(
|
|
94
|
+
cd "$project_dir" 2>/dev/null && \
|
|
95
|
+
LOKI_TARGET_DIR="$target_dir" \
|
|
96
|
+
timeout 5 python3 -m memory.managed_memory.retrieve \
|
|
97
|
+
--query "completion-council verdict context" --top-k 3 \
|
|
98
|
+
> "$out_file" 2>/dev/null || true
|
|
99
|
+
) || true
|
|
100
|
+
if [ -s "$out_file" ]; then
|
|
101
|
+
echo "RELATED PRIOR VERDICTS:"
|
|
102
|
+
cat "$out_file"
|
|
103
|
+
fi
|
|
104
|
+
return 0
|
|
105
|
+
}
|
|
106
|
+
|
|
75
107
|
#===============================================================================
|
|
76
108
|
# Initialization
|
|
77
109
|
#===============================================================================
|
|
@@ -1366,6 +1398,11 @@ council_should_stop() {
|
|
|
1366
1398
|
return 1
|
|
1367
1399
|
fi
|
|
1368
1400
|
|
|
1401
|
+
# v6.83.0 Phase 1: silent no-op unless both managed flags are on.
|
|
1402
|
+
# Writes related prior verdicts into $TARGET_DIR/.loki/managed/council-augment.txt
|
|
1403
|
+
# which the council prompt assembly step can read and append to its prompt.
|
|
1404
|
+
council_augment_from_managed_memory >/dev/null 2>&1 || true
|
|
1405
|
+
|
|
1369
1406
|
# Check circuit breaker first (stagnation detection)
|
|
1370
1407
|
local circuit_triggered=false
|
|
1371
1408
|
if council_circuit_breaker_triggered; then
|
|
@@ -1396,6 +1433,27 @@ council_should_stop() {
|
|
|
1396
1433
|
# Store final council report
|
|
1397
1434
|
council_write_report
|
|
1398
1435
|
|
|
1436
|
+
# v6.83.0 Phase 1: shadow-write the final council verdict to the
|
|
1437
|
+
# managed memory store. Backgrounded + silent; flags gate the work
|
|
1438
|
+
# inside the Python module so no-op when off.
|
|
1439
|
+
if [ "${LOKI_MANAGED_AGENTS:-false}" = "true" ] && \
|
|
1440
|
+
[ "${LOKI_MANAGED_MEMORY:-false}" = "true" ]; then
|
|
1441
|
+
local _verdict_file="$loki_dir/council/verdicts/iteration-$ITERATION_COUNT.json"
|
|
1442
|
+
if [ ! -f "$_verdict_file" ]; then
|
|
1443
|
+
# Fall back to the round vote file as the verdict payload.
|
|
1444
|
+
_verdict_file="$COUNCIL_STATE_DIR/votes/round-${ITERATION_COUNT}.json"
|
|
1445
|
+
fi
|
|
1446
|
+
if [ -f "$_verdict_file" ]; then
|
|
1447
|
+
(
|
|
1448
|
+
cd "${PROJECT_DIR:-$(pwd)}" 2>/dev/null && \
|
|
1449
|
+
LOKI_TARGET_DIR="$loki_dir/.." \
|
|
1450
|
+
timeout 15 python3 -m memory.managed_memory.shadow_write \
|
|
1451
|
+
--verdict "$_verdict_file" >/dev/null 2>&1 || true
|
|
1452
|
+
) &
|
|
1453
|
+
disown 2>/dev/null || true
|
|
1454
|
+
fi
|
|
1455
|
+
fi
|
|
1456
|
+
|
|
1399
1457
|
return 0 # STOP
|
|
1400
1458
|
fi
|
|
1401
1459
|
|
package/autonomy/run.sh
CHANGED
|
@@ -644,6 +644,19 @@ LOKI_SESSION_MODEL="${LOKI_SESSION_MODEL:-sonnet}"
|
|
|
644
644
|
LOKI_LEGACY_TIER_SWITCHING="${LOKI_LEGACY_TIER_SWITCHING:-false}"
|
|
645
645
|
export LOKI_SESSION_MODEL LOKI_LEGACY_TIER_SWITCHING
|
|
646
646
|
|
|
647
|
+
# Managed Agents (v6.83.0 Phase 1): opt-in integration with Claude Managed Agents
|
|
648
|
+
# Memory store backend. Parent flag gates everything; child flags gate features.
|
|
649
|
+
# Both off (default) => zero behavior change from v6.82.0.
|
|
650
|
+
LOKI_MANAGED_AGENTS="${LOKI_MANAGED_AGENTS:-false}"
|
|
651
|
+
LOKI_MANAGED_MEMORY="${LOKI_MANAGED_MEMORY:-false}"
|
|
652
|
+
export LOKI_MANAGED_AGENTS LOKI_MANAGED_MEMORY
|
|
653
|
+
|
|
654
|
+
# Fail-fast: child on with parent off is a misconfiguration.
|
|
655
|
+
if [ "$LOKI_MANAGED_MEMORY" = "true" ] && [ "$LOKI_MANAGED_AGENTS" != "true" ]; then
|
|
656
|
+
echo "ERROR: LOKI_MANAGED_MEMORY=true requires LOKI_MANAGED_AGENTS=true" >&2
|
|
657
|
+
exit 2
|
|
658
|
+
fi
|
|
659
|
+
|
|
647
660
|
# Parallel Workflows (Git Worktrees)
|
|
648
661
|
PARALLEL_MODE=${LOKI_PARALLEL_MODE:-false}
|
|
649
662
|
MAX_WORKTREES=${LOKI_MAX_WORKTREES:-5}
|
|
@@ -3763,9 +3776,12 @@ track_iteration_complete() {
|
|
|
3763
3776
|
[ -z "$phase" ] && phase=$(python3 -c "import json; print(json.load(open('.loki/state/orchestrator.json')).get('currentPhase', 'unknown'))" 2>/dev/null || echo "unknown")
|
|
3764
3777
|
|
|
3765
3778
|
# Read token data from context tracker output (v5.42.0)
|
|
3779
|
+
# v6.82.0: also capture cache_read_tokens / cache_creation_tokens for
|
|
3780
|
+
# prompt-cache hit-rate analysis (S1.1 prompt restructure).
|
|
3766
3781
|
local iter_input=0 iter_output=0 iter_cost=0
|
|
3782
|
+
local iter_cache_read=0 iter_cache_creation=0
|
|
3767
3783
|
if [ -f ".loki/context/tracking.json" ]; then
|
|
3768
|
-
read iter_input iter_output iter_cost < <(python3 -c "
|
|
3784
|
+
read iter_input iter_output iter_cost iter_cache_read iter_cache_creation < <(python3 -c "
|
|
3769
3785
|
import json
|
|
3770
3786
|
try:
|
|
3771
3787
|
t = json.load(open('.loki/context/tracking.json'))
|
|
@@ -3773,11 +3789,17 @@ try:
|
|
|
3773
3789
|
match = [i for i in iters if i.get('iteration') == $iteration]
|
|
3774
3790
|
if match:
|
|
3775
3791
|
m = match[-1]
|
|
3776
|
-
print(
|
|
3792
|
+
print(
|
|
3793
|
+
m.get('input_tokens', 0),
|
|
3794
|
+
m.get('output_tokens', 0),
|
|
3795
|
+
m.get('cost_usd', 0),
|
|
3796
|
+
m.get('cache_read_tokens', 0),
|
|
3797
|
+
m.get('cache_creation_tokens', 0),
|
|
3798
|
+
)
|
|
3777
3799
|
else:
|
|
3778
|
-
print(0, 0, 0)
|
|
3779
|
-
except: print(0, 0, 0)
|
|
3780
|
-
" 2>/dev/null || echo "0 0 0")
|
|
3800
|
+
print(0, 0, 0, 0, 0)
|
|
3801
|
+
except: print(0, 0, 0, 0, 0)
|
|
3802
|
+
" 2>/dev/null || echo "0 0 0 0 0")
|
|
3781
3803
|
fi
|
|
3782
3804
|
|
|
3783
3805
|
cat > ".loki/metrics/efficiency/iteration-${iteration}.json" << EFF_EOF
|
|
@@ -3790,6 +3812,8 @@ except: print(0, 0, 0)
|
|
|
3790
3812
|
"status": "$status_str",
|
|
3791
3813
|
"input_tokens": ${iter_input:-0},
|
|
3792
3814
|
"output_tokens": ${iter_output:-0},
|
|
3815
|
+
"cache_read_tokens": ${iter_cache_read:-0},
|
|
3816
|
+
"cache_creation_tokens": ${iter_cache_creation:-0},
|
|
3793
3817
|
"cost_usd": ${iter_cost:-0},
|
|
3794
3818
|
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
3795
3819
|
}
|
|
@@ -7596,18 +7620,87 @@ except Exception:
|
|
|
7596
7620
|
return 0
|
|
7597
7621
|
}
|
|
7598
7622
|
|
|
7599
|
-
# Check if
|
|
7623
|
+
# Check if the loki_complete_task MCP tool was invoked in this iteration.
|
|
7624
|
+
# The tool writes a payload to .loki/signals/TASK_COMPLETION_CLAIMED with the
|
|
7625
|
+
# structured completion claim. When the signal exists, we read it, log the
|
|
7626
|
+
# structured event, and consume (remove) the file. Returns 0 on detection.
|
|
7627
|
+
#
|
|
7628
|
+
# Output on stdout: the JSON payload (for callers that want to log it).
|
|
7629
|
+
check_task_completion_signal() {
|
|
7630
|
+
local signal_file=".loki/signals/TASK_COMPLETION_CLAIMED"
|
|
7631
|
+
if [ ! -f "$signal_file" ]; then
|
|
7632
|
+
return 1
|
|
7633
|
+
fi
|
|
7634
|
+
|
|
7635
|
+
local payload
|
|
7636
|
+
payload=$(cat "$signal_file" 2>/dev/null || echo "")
|
|
7637
|
+
if [ -z "$payload" ]; then
|
|
7638
|
+
# Empty signal -- treat as noise and clean up
|
|
7639
|
+
rm -f "$signal_file" 2>/dev/null
|
|
7640
|
+
return 1
|
|
7641
|
+
fi
|
|
7642
|
+
|
|
7643
|
+
# Emit a structured event for observability (best-effort).
|
|
7644
|
+
local statement evidence confidence
|
|
7645
|
+
statement=$(python3 -c "
|
|
7646
|
+
import json, sys
|
|
7647
|
+
try:
|
|
7648
|
+
d = json.loads(sys.stdin.read())
|
|
7649
|
+
print(d.get('statement',''))
|
|
7650
|
+
except Exception:
|
|
7651
|
+
pass
|
|
7652
|
+
" <<< "$payload" 2>/dev/null || echo "")
|
|
7653
|
+
evidence=$(python3 -c "
|
|
7654
|
+
import json, sys
|
|
7655
|
+
try:
|
|
7656
|
+
d = json.loads(sys.stdin.read())
|
|
7657
|
+
print(d.get('evidence',''))
|
|
7658
|
+
except Exception:
|
|
7659
|
+
pass
|
|
7660
|
+
" <<< "$payload" 2>/dev/null || echo "")
|
|
7661
|
+
confidence=$(python3 -c "
|
|
7662
|
+
import json, sys
|
|
7663
|
+
try:
|
|
7664
|
+
d = json.loads(sys.stdin.read())
|
|
7665
|
+
print(d.get('confidence','medium'))
|
|
7666
|
+
except Exception:
|
|
7667
|
+
print('medium')
|
|
7668
|
+
" <<< "$payload" 2>/dev/null || echo "medium")
|
|
7669
|
+
|
|
7670
|
+
emit_event_json "task_completion_claim" \
|
|
7671
|
+
"statement=${statement:0:500}" \
|
|
7672
|
+
"confidence=${confidence}" \
|
|
7673
|
+
"evidence_length=${#evidence}"
|
|
7674
|
+
|
|
7675
|
+
# Return the payload on stdout
|
|
7676
|
+
printf '%s\n' "$payload"
|
|
7677
|
+
|
|
7678
|
+
# Consume the signal (next iteration would otherwise re-trigger)
|
|
7679
|
+
rm -f "$signal_file" 2>/dev/null
|
|
7680
|
+
return 0
|
|
7681
|
+
}
|
|
7682
|
+
|
|
7683
|
+
# Check if completion promise is fulfilled in log output.
|
|
7684
|
+
#
|
|
7685
|
+
# As of v6.82.0, the default path is the MCP tool `loki_complete_task`
|
|
7686
|
+
# (detected via check_task_completion_signal above). The legacy grep-based
|
|
7687
|
+
# detection is retained behind LOKI_LEGACY_COMPLETION_MATCH=true for rollback.
|
|
7600
7688
|
check_completion_promise() {
|
|
7601
7689
|
local log_file="$1"
|
|
7602
7690
|
|
|
7603
|
-
#
|
|
7604
|
-
if
|
|
7691
|
+
# New default: structured signal from the loki_complete_task MCP tool.
|
|
7692
|
+
if check_task_completion_signal >/dev/null 2>&1; then
|
|
7605
7693
|
return 0
|
|
7606
7694
|
fi
|
|
7607
7695
|
|
|
7608
|
-
#
|
|
7609
|
-
if [
|
|
7610
|
-
|
|
7696
|
+
# Legacy grep fallback (opt-in via env flag for rollback).
|
|
7697
|
+
if [ "${LOKI_LEGACY_COMPLETION_MATCH:-false}" = "true" ]; then
|
|
7698
|
+
if grep -q "COMPLETION PROMISE FULFILLED" "$log_file" 2>/dev/null; then
|
|
7699
|
+
return 0
|
|
7700
|
+
fi
|
|
7701
|
+
if [ -n "$COMPLETION_PROMISE" ] && grep -qF "$COMPLETION_PROMISE" "$log_file" 2>/dev/null; then
|
|
7702
|
+
return 0
|
|
7703
|
+
fi
|
|
7611
7704
|
fi
|
|
7612
7705
|
|
|
7613
7706
|
return 1
|
|
@@ -7897,6 +7990,32 @@ try:
|
|
|
7897
7990
|
except Exception as e:
|
|
7898
7991
|
pass # Silently fail if memory not available
|
|
7899
7992
|
PYEOF
|
|
7993
|
+
|
|
7994
|
+
# v6.83.0 Phase 1: RARV-C REASON augment. When both managed flags are on,
|
|
7995
|
+
# pull related prior verdicts from the Claude Managed Agents store and
|
|
7996
|
+
# append them AFTER local results. 5s hard timeout so a slow remote never
|
|
7997
|
+
# blocks the loop. On timeout or error, emit a fallback event and continue.
|
|
7998
|
+
if [ "$LOKI_MANAGED_AGENTS" = "true" ] && [ "$LOKI_MANAGED_MEMORY" = "true" ]; then
|
|
7999
|
+
local managed_start_ms
|
|
8000
|
+
managed_start_ms=$(python3 -c "import time; print(int(time.time()*1000))" 2>/dev/null || echo "0")
|
|
8001
|
+
local managed_out
|
|
8002
|
+
managed_out=$(
|
|
8003
|
+
cd "$PROJECT_DIR" 2>/dev/null && \
|
|
8004
|
+
LOKI_TARGET_DIR="$target_dir" \
|
|
8005
|
+
timeout 5 python3 -m memory.managed_memory.retrieve \
|
|
8006
|
+
--query "$goal" --top-k 3 2>/dev/null || true
|
|
8007
|
+
)
|
|
8008
|
+
if [ -n "$managed_out" ]; then
|
|
8009
|
+
echo ""
|
|
8010
|
+
echo "RELATED PRIOR LEARNINGS (managed store):"
|
|
8011
|
+
echo "$managed_out"
|
|
8012
|
+
else
|
|
8013
|
+
# No output could mean: flags off (unreachable here), timeout, or
|
|
8014
|
+
# zero hits. Emit a fallback event only if a timeout likely occurred.
|
|
8015
|
+
LOKI_TARGET_DIR="$target_dir" \
|
|
8016
|
+
python3 -c "from memory.managed_memory.events import emit_managed_event; emit_managed_event('managed_memory_retrieve_empty', {'phase': '$phase'})" 2>/dev/null || true
|
|
8017
|
+
fi
|
|
8018
|
+
fi
|
|
7900
8019
|
}
|
|
7901
8020
|
|
|
7902
8021
|
# Store episode trace after task completion
|
|
@@ -8000,14 +8119,21 @@ auto_capture_episode() {
|
|
|
8000
8119
|
fi
|
|
8001
8120
|
|
|
8002
8121
|
# Pass all context via environment variables (prevents injection)
|
|
8122
|
+
# v6.83.0: also stash the resolved episode path so the bash caller can
|
|
8123
|
+
# optionally shadow-write it to the managed store if importance >= 0.6.
|
|
8124
|
+
local episode_path_file="/tmp/loki-episode-path-$$"
|
|
8125
|
+
: > "$episode_path_file"
|
|
8003
8126
|
_LOKI_PROJECT_DIR="$PROJECT_DIR" _LOKI_TARGET_DIR="$target_dir" \
|
|
8004
8127
|
_LOKI_ITERATION="$iteration" _LOKI_EXIT_CODE="$exit_code" \
|
|
8005
8128
|
_LOKI_RARV_PHASE="$rarv_phase" _LOKI_GOAL="$goal" \
|
|
8006
8129
|
_LOKI_DURATION="$duration" _LOKI_OUTCOME="$outcome" \
|
|
8007
8130
|
_LOKI_FILES_MODIFIED="$files_modified" _LOKI_GIT_COMMIT="$git_commit" \
|
|
8131
|
+
_LOKI_EPISODE_PATH_FILE="$episode_path_file" \
|
|
8008
8132
|
python3 << 'PYEOF' 2>/dev/null || true
|
|
8009
8133
|
import sys
|
|
8010
8134
|
import os
|
|
8135
|
+
import json
|
|
8136
|
+
from pathlib import Path
|
|
8011
8137
|
|
|
8012
8138
|
project_dir = os.environ.get('_LOKI_PROJECT_DIR', '')
|
|
8013
8139
|
target_dir = os.environ.get('_LOKI_TARGET_DIR', '.')
|
|
@@ -8018,6 +8144,7 @@ duration = os.environ.get('_LOKI_DURATION', '0')
|
|
|
8018
8144
|
outcome = os.environ.get('_LOKI_OUTCOME', 'success')
|
|
8019
8145
|
files_modified = os.environ.get('_LOKI_FILES_MODIFIED', '')
|
|
8020
8146
|
git_commit = os.environ.get('_LOKI_GIT_COMMIT', '')
|
|
8147
|
+
path_out_file = os.environ.get('_LOKI_EPISODE_PATH_FILE', '')
|
|
8021
8148
|
|
|
8022
8149
|
sys.path.insert(0, project_dir)
|
|
8023
8150
|
try:
|
|
@@ -8040,9 +8167,47 @@ try:
|
|
|
8040
8167
|
trace.files_modified = [f for f in files_modified.split('|') if f] if files_modified else []
|
|
8041
8168
|
|
|
8042
8169
|
engine.store_episode(trace)
|
|
8170
|
+
|
|
8171
|
+
# v6.83.0: surface the on-disk episode path + importance so bash can
|
|
8172
|
+
# decide whether to shadow-write. Writing to a known file (not stdout)
|
|
8173
|
+
# keeps the existing stdout contract intact.
|
|
8174
|
+
try:
|
|
8175
|
+
importance = float(getattr(trace, 'importance', 0.0) or 0.0)
|
|
8176
|
+
except (TypeError, ValueError):
|
|
8177
|
+
importance = 0.0
|
|
8178
|
+
episode_file = Path(f'{target_dir}/.loki/memory/episodic') / f'{trace.id}.json'
|
|
8179
|
+
if path_out_file:
|
|
8180
|
+
try:
|
|
8181
|
+
with open(path_out_file, 'w', encoding='utf-8') as f:
|
|
8182
|
+
json.dump({'path': str(episode_file), 'importance': importance}, f)
|
|
8183
|
+
except OSError:
|
|
8184
|
+
pass
|
|
8043
8185
|
except Exception:
|
|
8044
8186
|
pass # Silently fail -- memory capture must never break the loop
|
|
8045
8187
|
PYEOF
|
|
8188
|
+
|
|
8189
|
+
# v6.83.0 Phase 1: RARV-C REFLECT/VERIFY shadow-write. Only when both
|
|
8190
|
+
# managed flags are on AND the episode meets the consolidation importance
|
|
8191
|
+
# threshold (>= 0.6). Fully non-blocking (backgrounded subprocess).
|
|
8192
|
+
if [ "$LOKI_MANAGED_AGENTS" = "true" ] && [ "$LOKI_MANAGED_MEMORY" = "true" ] \
|
|
8193
|
+
&& [ -s "$episode_path_file" ]; then
|
|
8194
|
+
local _ep_path _ep_imp
|
|
8195
|
+
_ep_path=$(python3 -c "import json,sys; d=json.load(open(sys.argv[1])); print(d.get('path',''))" "$episode_path_file" 2>/dev/null || echo "")
|
|
8196
|
+
_ep_imp=$(python3 -c "import json,sys; d=json.load(open(sys.argv[1])); print(d.get('importance',0.0))" "$episode_path_file" 2>/dev/null || echo "0")
|
|
8197
|
+
if [ -n "$_ep_path" ] && [ -f "$_ep_path" ]; then
|
|
8198
|
+
local _above_threshold
|
|
8199
|
+
_above_threshold=$(python3 -c "print('yes' if float('$_ep_imp') >= 0.6 else 'no')" 2>/dev/null || echo "no")
|
|
8200
|
+
if [ "$_above_threshold" = "yes" ]; then
|
|
8201
|
+
(
|
|
8202
|
+
cd "$PROJECT_DIR" 2>/dev/null && \
|
|
8203
|
+
LOKI_TARGET_DIR="$target_dir" \
|
|
8204
|
+
timeout 15 python3 -m memory.managed_memory.shadow_write --path "$_ep_path" >/dev/null 2>&1 || true
|
|
8205
|
+
) &
|
|
8206
|
+
disown 2>/dev/null || true
|
|
8207
|
+
fi
|
|
8208
|
+
fi
|
|
8209
|
+
fi
|
|
8210
|
+
rm -f "$episode_path_file" 2>/dev/null || true
|
|
8046
8211
|
}
|
|
8047
8212
|
|
|
8048
8213
|
# Run memory consolidation pipeline
|
|
@@ -8360,12 +8525,16 @@ build_prompt() {
|
|
|
8360
8525
|
# Ralph Wiggum Mode - Reason-Act-Reflect-VERIFY cycle with self-verification loop (Boris Cherny pattern)
|
|
8361
8526
|
local rarv_instruction="RALPH WIGGUM MODE ACTIVE. Use Reason-Act-Reflect-VERIFY cycle: 1) REASON - READ .loki/CONTINUITY.md including 'Mistakes & Learnings' section to avoid past errors. CHECK .loki/state/relevant-learnings.json for cross-project learnings from previous projects (mistakes to avoid, patterns to apply). Check .loki/state/ and .loki/queue/, identify next task. CHECK .loki/state/resources.json for system resource warnings - if CPU or memory is high, reduce parallel agent spawning or pause non-critical tasks. Limit to MAX_PARALLEL_AGENTS=${MAX_PARALLEL_AGENTS}. If queue empty, find new improvements. 2) ACT - Execute task, write code, commit changes atomically (git checkpoint). 3) REFLECT - Update .loki/CONTINUITY.md with progress, update state, identify NEXT improvement. Save valuable learnings for future projects. 4) VERIFY - Run automated tests (unit, integration, E2E), check compilation/build, verify against spec. IF VERIFICATION FAILS: a) Capture error details (stack trace, logs), b) Analyze root cause, c) UPDATE 'Mistakes & Learnings' in CONTINUITY.md with what failed, why, and how to prevent, d) Rollback to last good git checkpoint if needed, e) Apply learning and RETRY from REASON. If verification passes, mark task complete and continue. This self-verification loop achieves 2-3x quality improvement. CRITICAL: There is NEVER a 'finished' state - always find the next improvement, optimization, test, or feature."
|
|
8362
8527
|
|
|
8363
|
-
# Completion
|
|
8528
|
+
# Completion instruction (S0.2 -- structured tool call).
|
|
8529
|
+
# When PRD requirements are implemented, tests pass, and the checklist is
|
|
8530
|
+
# at or near 100%, the agent MUST invoke the `loki_complete_task` MCP tool
|
|
8531
|
+
# (defined in mcp/server.py) with completion_statement + evidence fields,
|
|
8532
|
+
# instead of emitting a prose completion string.
|
|
8364
8533
|
local completion_instruction=""
|
|
8365
8534
|
if [ -n "$COMPLETION_PROMISE" ]; then
|
|
8366
|
-
completion_instruction="COMPLETION_PROMISE: [$COMPLETION_PROMISE].
|
|
8535
|
+
completion_instruction="COMPLETION_PROMISE: [$COMPLETION_PROMISE]. When all PRD requirements are implemented, tests pass, and the PRD checklist is at or near 100%, invoke the loki_complete_task MCP tool with your completion_statement and evidence (cite tests that passed, checklist items verified, files created/modified). Do NOT emit a completion string in prose -- use the tool call."
|
|
8367
8536
|
else
|
|
8368
|
-
completion_instruction="NO COMPLETION PROMISE SET. Continue finding improvements. The Completion Council will evaluate your progress periodically. Iteration $iteration of max $MAX_ITERATIONS."
|
|
8537
|
+
completion_instruction="NO COMPLETION PROMISE SET. Continue finding improvements. The Completion Council will evaluate your progress periodically. Iteration $iteration of max $MAX_ITERATIONS. If you do decide the task is complete, invoke the loki_complete_task MCP tool with a structured statement and evidence rather than emitting prose."
|
|
8369
8538
|
fi
|
|
8370
8539
|
|
|
8371
8540
|
# Core autonomous instructions - NO questions, NO waiting, NEVER say done
|
|
@@ -8373,7 +8542,7 @@ build_prompt() {
|
|
|
8373
8542
|
if [ "$AUTONOMY_MODE" = "perpetual" ] || [ "$PERPETUAL_MODE" = "true" ]; then
|
|
8374
8543
|
autonomous_suffix="CRITICAL AUTONOMY RULES: 1) NEVER ask questions - just decide. 2) NEVER wait for confirmation - just act. 3) NEVER say 'done' or 'complete' - there's always more to improve. 4) NEVER stop voluntarily - if out of tasks, create new ones (add tests, optimize, refactor, add features). 5) Work continues PERPETUALLY. Even if PRD is implemented, find bugs, add tests, improve UX, optimize performance."
|
|
8375
8544
|
else
|
|
8376
|
-
autonomous_suffix="CRITICAL AUTONOMY RULES: 1) NEVER ask questions - just decide. 2) NEVER wait for confirmation - just act. 3) When all PRD requirements are implemented and tests pass,
|
|
8545
|
+
autonomous_suffix="CRITICAL AUTONOMY RULES: 1) NEVER ask questions - just decide. 2) NEVER wait for confirmation - just act. 3) When all PRD requirements are implemented and tests pass, invoke the loki_complete_task MCP tool (completion_statement='$COMPLETION_PROMISE' plus evidence + confidence). Do not emit completion prose. 4) If out of tasks but PRD is not fully implemented, continue working on remaining requirements. 5) Focus on completing PRD scope, not endless improvements."
|
|
8377
8546
|
fi
|
|
8378
8547
|
|
|
8379
8548
|
# Skill files are always copied to .loki/skills/ for all providers
|
|
@@ -8655,42 +8824,154 @@ except Exception:
|
|
|
8655
8824
|
fi
|
|
8656
8825
|
fi
|
|
8657
8826
|
|
|
8658
|
-
#
|
|
8659
|
-
#
|
|
8827
|
+
# S1.1 -- Static-first prompt assembly with cache-breakpoint marker.
|
|
8828
|
+
#
|
|
8829
|
+
# The prior shape (v<=6.81.x) concatenated ~13 dynamic blobs BEFORE the
|
|
8830
|
+
# 4-5 static instruction blobs, which destroyed Claude's prefix cache on
|
|
8831
|
+
# every iteration. The new layout places the stable instruction set first
|
|
8832
|
+
# (prd_anchor + RARV/SDLC/autonomy/memory instructions), emits a literal
|
|
8833
|
+
# [CACHE_BREAKPOINT] marker, then appends the volatile per-iteration
|
|
8834
|
+
# context inside a <dynamic_context> tag.
|
|
8835
|
+
#
|
|
8836
|
+
# The [CACHE_BREAKPOINT] marker is a documentation anchor today. When the
|
|
8837
|
+
# Claude CLI migration exposes cache_control, the orchestrator can split
|
|
8838
|
+
# the prompt at this marker and set cache_control on the prefix half.
|
|
8839
|
+
#
|
|
8840
|
+
# Rollback: set LOKI_LEGACY_PROMPT_ORDERING=true to restore the previous
|
|
8841
|
+
# dynamic-first concatenation order.
|
|
8842
|
+
|
|
8843
|
+
if [ "${LOKI_LEGACY_PROMPT_ORDERING:-false}" = "true" ]; then
|
|
8844
|
+
# Legacy dynamic-first ordering (pre-v6.82.0). Retained for rollback.
|
|
8845
|
+
if [ "${PROVIDER_DEGRADED:-false}" = "true" ]; then
|
|
8846
|
+
local _legacy_prd_content=""
|
|
8847
|
+
if [ -n "$prd" ] && [ -f "$prd" ]; then
|
|
8848
|
+
_legacy_prd_content=$(head -c 4000 "$prd")
|
|
8849
|
+
fi
|
|
8850
|
+
if [ $retry -eq 0 ]; then
|
|
8851
|
+
if [ -n "$prd" ]; then
|
|
8852
|
+
echo "You are a coding assistant. Read and implement the requirements from the PRD below. Write working code, run tests if possible, and commit changes. ${human_directive:+Priority: $human_directive} ${queue_tasks:+Tasks: $queue_tasks} PRD contents: $_legacy_prd_content"
|
|
8853
|
+
else
|
|
8854
|
+
echo "You are a coding assistant. Analyze this codebase and suggest improvements. Write working code and commit changes. ${human_directive:+Priority: $human_directive} ${queue_tasks:+Tasks: $queue_tasks}"
|
|
8855
|
+
fi
|
|
8856
|
+
else
|
|
8857
|
+
if [ -n "$prd" ]; then
|
|
8858
|
+
echo "You are a coding assistant. Continue working on iteration $iteration. Review what exists, implement remaining PRD requirements, fix any issues, add tests. ${human_directive:+Priority: $human_directive} ${queue_tasks:+Tasks: $queue_tasks} PRD contents: $_legacy_prd_content"
|
|
8859
|
+
else
|
|
8860
|
+
echo "You are a coding assistant. Continue working on iteration $iteration. Review what exists, improve code, fix bugs, add tests. ${human_directive:+Priority: $human_directive} ${queue_tasks:+Tasks: $queue_tasks}"
|
|
8861
|
+
fi
|
|
8862
|
+
fi
|
|
8863
|
+
else
|
|
8864
|
+
if [ $retry -eq 0 ]; then
|
|
8865
|
+
if [ -n "$prd" ]; then
|
|
8866
|
+
echo "Loki Mode with PRD at $prd. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $magic_context $checklist_status $app_runner_info $playwright_info $memory_context_section $rarv_instruction $memory_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
8867
|
+
else
|
|
8868
|
+
echo "Loki Mode. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $magic_context $checklist_status $app_runner_info $playwright_info $memory_context_section $analysis_instruction $rarv_instruction $memory_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
8869
|
+
fi
|
|
8870
|
+
else
|
|
8871
|
+
if [ -n "$prd" ]; then
|
|
8872
|
+
echo "Loki Mode - Resume iteration #$iteration (retry #$retry). PRD: $prd. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $magic_context $checklist_status $app_runner_info $playwright_info $memory_context_section $rarv_instruction $memory_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
8873
|
+
else
|
|
8874
|
+
echo "Loki Mode - Resume iteration #$iteration (retry #$retry). $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $magic_context $checklist_status $app_runner_info $playwright_info $memory_context_section Use .loki/generated-prd.md if exists. $rarv_instruction $memory_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
8875
|
+
fi
|
|
8876
|
+
fi
|
|
8877
|
+
fi
|
|
8878
|
+
return 0
|
|
8879
|
+
fi
|
|
8880
|
+
|
|
8881
|
+
# --- New static-first layout (v6.82.0+) ---
|
|
8882
|
+
#
|
|
8883
|
+
# assemble_prompt_static outputs the cache-stable prefix:
|
|
8884
|
+
# <loki_system>
|
|
8885
|
+
# {prd_anchor}
|
|
8886
|
+
# {rarv_instruction + sdlc_instruction + autonomous_suffix + memory_instruction}
|
|
8887
|
+
# </loki_system>
|
|
8888
|
+
# [CACHE_BREAKPOINT]
|
|
8889
|
+
#
|
|
8890
|
+
# assemble_prompt_dynamic outputs the volatile tail wrapped in
|
|
8891
|
+
# <dynamic_context iteration=".." retry=".."> ... </dynamic_context>.
|
|
8892
|
+
#
|
|
8893
|
+
# Keeping these as inline local helpers (nested functions via eval are
|
|
8894
|
+
# awkward in bash) -- we emit them as two contiguous printf blocks so the
|
|
8895
|
+
# logic is self-documenting and byte-reproducible.
|
|
8896
|
+
|
|
8660
8897
|
if [ "${PROVIDER_DEGRADED:-false}" = "true" ]; then
|
|
8898
|
+
# Degraded providers: simpler wording, but still static-first.
|
|
8661
8899
|
local prd_content=""
|
|
8662
8900
|
if [ -n "$prd" ] && [ -f "$prd" ]; then
|
|
8663
8901
|
prd_content=$(head -c 4000 "$prd")
|
|
8664
8902
|
fi
|
|
8665
8903
|
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8904
|
+
local degraded_prd_anchor="Loki Mode"
|
|
8905
|
+
[ -n "$prd" ] && degraded_prd_anchor="Loki Mode with PRD"
|
|
8906
|
+
|
|
8907
|
+
# STATIC PREFIX (cache-stable across iterations)
|
|
8908
|
+
printf '<loki_system>\n'
|
|
8909
|
+
printf '%s\n' "$degraded_prd_anchor"
|
|
8910
|
+
if [ -n "$prd" ]; then
|
|
8911
|
+
printf 'You are a coding assistant. Read and implement the requirements from the PRD. Write working code, run tests if possible, and commit changes.\n'
|
|
8672
8912
|
else
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
|
|
8913
|
+
printf 'You are a coding assistant. Analyze this codebase and suggest improvements. Write working code and commit changes.\n'
|
|
8914
|
+
fi
|
|
8915
|
+
printf '</loki_system>\n'
|
|
8916
|
+
printf '[CACHE_BREAKPOINT]\n'
|
|
8917
|
+
|
|
8918
|
+
# DYNAMIC TAIL (changes every iteration)
|
|
8919
|
+
printf '<dynamic_context iteration="%s" retry="%s">\n' "$iteration" "$retry"
|
|
8920
|
+
[ -n "$human_directive" ] && printf 'Priority: %s\n' "$human_directive"
|
|
8921
|
+
[ -n "$queue_tasks" ] && printf 'Tasks: %s\n' "$queue_tasks"
|
|
8922
|
+
if [ -n "$prd" ]; then
|
|
8923
|
+
printf 'PRD contents: %s\n' "$prd_content"
|
|
8678
8924
|
fi
|
|
8925
|
+
printf '</dynamic_context>\n'
|
|
8926
|
+
return 0
|
|
8927
|
+
fi
|
|
8928
|
+
|
|
8929
|
+
# Full-featured providers (Claude, etc.)
|
|
8930
|
+
local prd_anchor
|
|
8931
|
+
if [ -n "$prd" ]; then
|
|
8932
|
+
prd_anchor="Loki Mode with PRD at $prd"
|
|
8679
8933
|
else
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
8934
|
+
prd_anchor="Loki Mode"
|
|
8935
|
+
fi
|
|
8936
|
+
|
|
8937
|
+
# STATIC PREFIX (cache-stable across iterations).
|
|
8938
|
+
# Order is deterministic so the prefix is byte-identical for iter N and N+1.
|
|
8939
|
+
printf '<loki_system>\n'
|
|
8940
|
+
printf '%s\n' "$prd_anchor"
|
|
8941
|
+
printf '%s\n' "$rarv_instruction"
|
|
8942
|
+
printf '%s\n' "$sdlc_instruction"
|
|
8943
|
+
printf '%s\n' "$autonomous_suffix"
|
|
8944
|
+
printf '%s\n' "$memory_instruction"
|
|
8945
|
+
# For codebase-analysis mode (no PRD), analysis_instruction is part of the
|
|
8946
|
+
# static prefix so it remains cache-stable.
|
|
8947
|
+
if [ -z "$prd" ]; then
|
|
8948
|
+
printf '%s\n' "$analysis_instruction"
|
|
8949
|
+
fi
|
|
8950
|
+
printf '</loki_system>\n'
|
|
8951
|
+
printf '[CACHE_BREAKPOINT]\n'
|
|
8952
|
+
|
|
8953
|
+
# DYNAMIC TAIL -- all per-iteration context goes here.
|
|
8954
|
+
printf '<dynamic_context iteration="%s" retry="%s">\n' "$iteration" "$retry"
|
|
8955
|
+
if [ $retry -gt 0 ]; then
|
|
8956
|
+
if [ -n "$prd" ]; then
|
|
8957
|
+
printf 'Resume iteration #%s (retry #%s). PRD: %s\n' "$iteration" "$retry" "$prd"
|
|
8686
8958
|
else
|
|
8687
|
-
|
|
8688
|
-
echo "Loki Mode - Resume iteration #$iteration (retry #$retry). PRD: $prd. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $magic_context $checklist_status $app_runner_info $playwright_info $memory_context_section $rarv_instruction $memory_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
8689
|
-
else
|
|
8690
|
-
echo "Loki Mode - Resume iteration #$iteration (retry #$retry). $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $magic_context $checklist_status $app_runner_info $playwright_info $memory_context_section Use .loki/generated-prd.md if exists. $rarv_instruction $memory_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
8691
|
-
fi
|
|
8959
|
+
printf 'Resume iteration #%s (retry #%s). Use .loki/generated-prd.md if exists.\n' "$iteration" "$retry"
|
|
8692
8960
|
fi
|
|
8693
8961
|
fi
|
|
8962
|
+
[ -n "$human_directive" ] && printf '%s\n' "$human_directive"
|
|
8963
|
+
[ -n "$gate_failure_context" ] && printf '%s\n' "$gate_failure_context"
|
|
8964
|
+
[ -n "$queue_tasks" ] && printf '%s\n' "$queue_tasks"
|
|
8965
|
+
[ -n "$bmad_context" ] && printf '%s\n' "$bmad_context"
|
|
8966
|
+
[ -n "$openspec_context" ] && printf '%s\n' "$openspec_context"
|
|
8967
|
+
[ -n "$mirofish_context" ] && printf '%s\n' "$mirofish_context"
|
|
8968
|
+
[ -n "$magic_context" ] && printf '%s\n' "$magic_context"
|
|
8969
|
+
[ -n "$checklist_status" ] && printf '%s\n' "$checklist_status"
|
|
8970
|
+
[ -n "$app_runner_info" ] && printf '%s\n' "$app_runner_info"
|
|
8971
|
+
[ -n "$playwright_info" ] && printf '%s\n' "$playwright_info"
|
|
8972
|
+
[ -n "$memory_context_section" ] && printf '%s\n' "$memory_context_section"
|
|
8973
|
+
printf '%s\n' "$completion_instruction"
|
|
8974
|
+
printf '</dynamic_context>\n'
|
|
8694
8975
|
}
|
|
8695
8976
|
|
|
8696
8977
|
#===============================================================================
|
|
@@ -10317,12 +10598,21 @@ if __name__ == "__main__":
|
|
|
10317
10598
|
return 0
|
|
10318
10599
|
fi
|
|
10319
10600
|
|
|
10320
|
-
#
|
|
10321
|
-
#
|
|
10322
|
-
|
|
10601
|
+
# Stop if either:
|
|
10602
|
+
# (a) the agent invoked the loki_complete_task MCP tool
|
|
10603
|
+
# (detected via .loki/signals/TASK_COMPLETION_CLAIMED), OR
|
|
10604
|
+
# (b) LOKI_LEGACY_COMPLETION_MATCH=true AND the completion
|
|
10605
|
+
# promise text appears in the iteration output.
|
|
10606
|
+
# The check_completion_promise() helper encapsulates both.
|
|
10607
|
+
# BUG-RUN-001: Use per-iteration output, not stale daily log.
|
|
10608
|
+
if check_completion_promise "$iter_output"; then
|
|
10323
10609
|
echo ""
|
|
10324
|
-
|
|
10325
|
-
|
|
10610
|
+
if [ -n "$COMPLETION_PROMISE" ]; then
|
|
10611
|
+
log_header "COMPLETION PROMISE FULFILLED: $COMPLETION_PROMISE"
|
|
10612
|
+
else
|
|
10613
|
+
log_header "TASK COMPLETION CLAIMED (via loki_complete_task)"
|
|
10614
|
+
fi
|
|
10615
|
+
log_info "Explicit completion signal detected."
|
|
10326
10616
|
# Run memory consolidation on successful completion
|
|
10327
10617
|
log_info "Running memory consolidation..."
|
|
10328
10618
|
run_memory_consolidation
|
package/dashboard/__init__.py
CHANGED
package/docs/INSTALLATION.md
CHANGED
package/mcp/__init__.py
CHANGED
package/mcp/requirements.txt
CHANGED