loki-mode 7.25.0 → 7.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/app-runner.sh +185 -14
- package/autonomy/run.sh +14 -4
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,12 +27,13 @@
|
|
|
27
27
|
- **Spec-driven, autonomous, with a built-in trust layer** -- Hand Loki a spec, walk away, come back to working code with tests. The full RARV-C closure loop (Reason - Act - Reflect - Verify - Close) runs until the work is actually done, not just attempted. The verified-completion evidence gate (`skills/quality-gates.md`) refuses any "done" claim on an empty git diff against the run-start commit, and blocks completion when tests run red, so "complete" means proven, not promised.
|
|
28
28
|
- **Production quality built in** -- 11 quality gates (`skills/quality-gates.md`), blind 3-reviewer code review (`run.sh:run_code_review()`), anti-sycophancy checks
|
|
29
29
|
- **Live App Preview** -- The dashboard embeds the locally-running app in an iframe so you can interact with it immediately during a build. Use `loki preview` (alias `loki open`) to print the URL and open it in your browser. Local-first: no hosted service, no vendor lock (v7.24.0).
|
|
30
|
+
- **Compose-first fullstack** -- When a spec needs more than one service (web + database + cache) Loki generates a 12-factor `docker-compose.yml` with healthchecks, `depends_on` wiring, env-var config, and a `.env.example`. The Live App Preview surfaces the web service URL (not a database port), and health reflects the web service's Docker healthcheck so a crashed app shows as crashed even when the database stays up. Single-service apps stay on a plain run command. All local-first, no hosted service (v7.26.0).
|
|
30
31
|
- **Intelligent `loki start`** -- For interactive foreground runs the dashboard auto-opens in the browser (cross-platform; skipped in CI, SSH-without-TTY, and piped runs; opt out with `LOKI_NO_AUTO_OPEN=1`). The completion summary shows "Your app is live at <url>" so you know exactly where to try what Loki just built. The autonomous loop passes Claude Code's `--effort`, `--max-budget-usd`, and `--fallback-model` on every iteration (each gated on CLI support and individual opt-out env vars) for better long-run unattended execution (v7.25.0).
|
|
31
32
|
- **Cross-project memory** -- Episodic/semantic/procedural memory with vector search; knowledge learned on one project surfaces on the next (v5.15.0+, see `memory/engine.py`)
|
|
32
33
|
- **Self-hosted and private** -- Your keys, your infrastructure, no data leaves your network
|
|
33
34
|
- **Legacy system healing** -- `loki heal` archaeology/stabilize/isolate/modernize/validate phases (v6.67.0, see `skills/healing.md`)
|
|
34
35
|
- **MCP server** -- 34 tools (including ChromaDB code search) plus 3 resources and 2 prompts (`mcp/server.py`, with managed-memory and magic tools registered from `mcp/managed_tools.py` and `mcp/magic_tools.py`)
|
|
35
|
-
- **Full-stack output** -- Source code, tests, Docker
|
|
36
|
+
- **Full-stack output** -- Source code, tests, Docker Compose stacks (multi-service with healthchecks), CI/CD pipelines, audit logs
|
|
36
37
|
- **Provider-agnostic** -- runs on Claude, Codex, Cline, or Aider with automatic failover (`loki-ts/src/runner/providers.ts`); no vendor lock-in. Gemini CLI deprecated v7.5.18; Antigravity CLI coming soon.
|
|
37
38
|
- **Open source** -- Free for personal, internal, and academic use.
|
|
38
39
|
|
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.26.0
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -383,4 +383,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
383
383
|
|
|
384
384
|
---
|
|
385
385
|
|
|
386
|
-
**v7.
|
|
386
|
+
**v7.26.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
7.
|
|
1
|
+
7.26.0
|
package/autonomy/app-runner.sh
CHANGED
|
@@ -43,6 +43,10 @@ _APP_RUNNER_PID=""
|
|
|
43
43
|
_APP_RUNNER_URL=""
|
|
44
44
|
_APP_RUNNER_IS_DOCKER=false
|
|
45
45
|
_APP_RUNNER_DOCKER_CONTAINER=""
|
|
46
|
+
# v7.26.0 (Phase 4): the identified primary web service of a compose project,
|
|
47
|
+
# used for service-aware health checks and the preview URL. Empty for
|
|
48
|
+
# non-compose runs or when identification falls back to legacy port parsing.
|
|
49
|
+
_APP_RUNNER_WEB_SERVICE=""
|
|
46
50
|
_APP_RUNNER_HAS_SETSID=false
|
|
47
51
|
_APP_RUNNER_CRASH_COUNT=0
|
|
48
52
|
_APP_RUNNER_RESTART_COUNT=0
|
|
@@ -146,6 +150,77 @@ _rotate_app_log() {
|
|
|
146
150
|
fi
|
|
147
151
|
}
|
|
148
152
|
|
|
153
|
+
# Identify the primary web service of a docker compose project and its
|
|
154
|
+
# published host port. Uses `docker compose config --format json` (fully
|
|
155
|
+
# resolved: env-interpolated, overrides merged) parsed with python3, so we do
|
|
156
|
+
# NOT hand-parse YAML. Precedence MATCHES the contract in COMPOSE_INSTRUCTION
|
|
157
|
+
# (run.sh build_prompt): (1) label loki.primary=true, (2) service named
|
|
158
|
+
# web/app, (3) service publishing a common web port, (4) first service with any
|
|
159
|
+
# published port. Echoes "service_name|published_port" on success, nothing on
|
|
160
|
+
# failure (caller falls back to legacy behavior). Never hard-fails.
|
|
161
|
+
# v7.26.0 (Phase 4): fixes the multi-service URL/health gaps (GAP #1-4).
|
|
162
|
+
_identify_compose_web_service() {
|
|
163
|
+
local base="${1:-${TARGET_DIR:-.}}"
|
|
164
|
+
local compose_dir
|
|
165
|
+
compose_dir=$(_app_runner_compose_dir "$base")
|
|
166
|
+
command -v docker >/dev/null 2>&1 || return 0
|
|
167
|
+
command -v python3 >/dev/null 2>&1 || return 0
|
|
168
|
+
local cfg
|
|
169
|
+
cfg=$(cd "$compose_dir" && docker compose config --format json 2>/dev/null) || return 0
|
|
170
|
+
[ -n "$cfg" ] || return 0
|
|
171
|
+
printf '%s' "$cfg" | python3 -c '
|
|
172
|
+
import json, sys
|
|
173
|
+
COMMON = ["3000", "8000", "8080", "5000", "4200", "5173", "80"]
|
|
174
|
+
try:
|
|
175
|
+
d = json.load(sys.stdin)
|
|
176
|
+
except Exception:
|
|
177
|
+
sys.exit(0)
|
|
178
|
+
services = d.get("services", {})
|
|
179
|
+
if not isinstance(services, dict) or not services:
|
|
180
|
+
sys.exit(0)
|
|
181
|
+
|
|
182
|
+
def published_ports(svc):
|
|
183
|
+
out = []
|
|
184
|
+
for p in (svc.get("ports") or []):
|
|
185
|
+
if isinstance(p, dict):
|
|
186
|
+
pub = p.get("published")
|
|
187
|
+
else:
|
|
188
|
+
pub = None
|
|
189
|
+
if pub is not None and str(pub).strip():
|
|
190
|
+
out.append(str(pub).strip())
|
|
191
|
+
return out
|
|
192
|
+
|
|
193
|
+
# (1) label loki.primary=true
|
|
194
|
+
for name, svc in services.items():
|
|
195
|
+
labels = svc.get("labels") or {}
|
|
196
|
+
if isinstance(labels, list):
|
|
197
|
+
labels = dict(x.split("=", 1) for x in labels if "=" in x)
|
|
198
|
+
if str(labels.get("loki.primary", "")).lower() == "true":
|
|
199
|
+
pp = published_ports(svc)
|
|
200
|
+
if pp:
|
|
201
|
+
print(name + "|" + pp[0]); sys.exit(0)
|
|
202
|
+
# (2) service named web/app
|
|
203
|
+
for cand in ("web", "app"):
|
|
204
|
+
svc = services.get(cand)
|
|
205
|
+
if svc:
|
|
206
|
+
pp = published_ports(svc)
|
|
207
|
+
if pp:
|
|
208
|
+
print(cand + "|" + pp[0]); sys.exit(0)
|
|
209
|
+
# (3) service publishing a common web port
|
|
210
|
+
for name, svc in services.items():
|
|
211
|
+
pp = published_ports(svc)
|
|
212
|
+
for cp in COMMON:
|
|
213
|
+
if cp in pp:
|
|
214
|
+
print(name + "|" + cp); sys.exit(0)
|
|
215
|
+
# (4) first service with any published port
|
|
216
|
+
for name, svc in services.items():
|
|
217
|
+
pp = published_ports(svc)
|
|
218
|
+
if pp:
|
|
219
|
+
print(name + "|" + pp[0]); sys.exit(0)
|
|
220
|
+
sys.exit(0)
|
|
221
|
+
' 2>/dev/null || return 0
|
|
222
|
+
}
|
|
223
|
+
|
|
149
224
|
# Detect port from project files
|
|
150
225
|
_detect_port() {
|
|
151
226
|
local method="$1"
|
|
@@ -158,18 +233,34 @@ _detect_port() {
|
|
|
158
233
|
|
|
159
234
|
case "$method" in
|
|
160
235
|
*docker\ compose*)
|
|
161
|
-
#
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
236
|
+
# v7.26.0: identify the PRIMARY WEB service and ITS published port
|
|
237
|
+
# via docker compose config (resolved JSON), so the preview URL and
|
|
238
|
+
# health check target the web service, not whichever port (e.g. a
|
|
239
|
+
# db/cache) appears first in the file. Falls back to the legacy
|
|
240
|
+
# first-port grep when docker/python is unavailable or no web
|
|
241
|
+
# service is found.
|
|
242
|
+
local web_info web_port
|
|
243
|
+
web_info=$(_identify_compose_web_service "${TARGET_DIR:-.}")
|
|
244
|
+
if [ -n "$web_info" ]; then
|
|
245
|
+
_APP_RUNNER_WEB_SERVICE="${web_info%%|*}"
|
|
246
|
+
web_port="${web_info##*|}"
|
|
247
|
+
fi
|
|
248
|
+
if [ -n "${web_port:-}" ] && [[ "$web_port" =~ ^[0-9]+$ ]]; then
|
|
249
|
+
_APP_RUNNER_PORT="$web_port"
|
|
165
250
|
else
|
|
166
|
-
|
|
251
|
+
# Legacy fallback: first published port from the compose file.
|
|
252
|
+
local compose_file
|
|
253
|
+
if [ -f "${TARGET_DIR:-.}/docker-compose.yml" ]; then
|
|
254
|
+
compose_file="${TARGET_DIR:-.}/docker-compose.yml"
|
|
255
|
+
else
|
|
256
|
+
compose_file="${TARGET_DIR:-.}/compose.yml"
|
|
257
|
+
fi
|
|
258
|
+
local port
|
|
259
|
+
# Handle both simple (HOST:CONTAINER) and IP-bound (IP:HOST:CONTAINER) port formats
|
|
260
|
+
# Also handle port ranges like "8080-8090:8080-8090" by taking the first port
|
|
261
|
+
port=$(grep -E '^\s*-\s*"?[0-9]' "$compose_file" 2>/dev/null | head -1 | sed 's/.*- *"*//;s/".*//;' | awk -F: '{print $(NF-1)}' | awk -F- '{print $1}')
|
|
262
|
+
_APP_RUNNER_PORT="${port:-8080}"
|
|
167
263
|
fi
|
|
168
|
-
local port
|
|
169
|
-
# Handle both simple (HOST:CONTAINER) and IP-bound (IP:HOST:CONTAINER) port formats
|
|
170
|
-
# Also handle port ranges like "8080-8090:8080-8090" by taking the first port
|
|
171
|
-
port=$(grep -E '^\s*-\s*"?[0-9]' "$compose_file" 2>/dev/null | head -1 | sed 's/.*- *"*//;s/".*//;' | awk -F: '{print $(NF-1)}' | awk -F- '{print $1}')
|
|
172
|
-
_APP_RUNNER_PORT="${port:-8080}"
|
|
173
264
|
;;
|
|
174
265
|
*docker\ build*)
|
|
175
266
|
local port
|
|
@@ -694,14 +785,64 @@ app_runner_health_check() {
|
|
|
694
785
|
# retries are handled in app_runner_start.
|
|
695
786
|
local running_containers
|
|
696
787
|
running_containers=$(LOKI_COMPOSE_HEALTH_TIMEOUT=1 _app_runner_compose_running_count "${TARGET_DIR:-.}")
|
|
697
|
-
if [ "${running_containers:-0}" -
|
|
788
|
+
if [ "${running_containers:-0}" -le 0 ]; then
|
|
789
|
+
# Nothing running at all.
|
|
790
|
+
_write_health "false"
|
|
791
|
+
_write_app_state "crashed"
|
|
792
|
+
return 1
|
|
793
|
+
fi
|
|
794
|
+
# v7.26.0 (Phase 4) GAP #4 fix: "some container is up" is NOT health for
|
|
795
|
+
# a multi-service stack. If we identified a primary web service, health
|
|
796
|
+
# keys on THAT service, not on whether any container (e.g. a db/cache) is
|
|
797
|
+
# up. Two signals, in order: (1) the web service's docker HEALTHCHECK
|
|
798
|
+
# result when one is declared (COMPOSE_INSTRUCTION mandates an HTTP
|
|
799
|
+
# healthcheck on the web service) -- "healthy" means actually serving,
|
|
800
|
+
# "unhealthy"/"starting" do not; (2) when no healthcheck is declared,
|
|
801
|
+
# fall back to the container lifecycle State (running), matching the
|
|
802
|
+
# codebase convention. Reads both fields from one `docker compose ps`.
|
|
803
|
+
if [ -n "${_APP_RUNNER_WEB_SERVICE:-}" ]; then
|
|
804
|
+
local _web_line _web_state _web_health
|
|
805
|
+
_web_line=$(cd "$(_app_runner_compose_dir "${TARGET_DIR:-.}")" \
|
|
806
|
+
&& docker compose ps --format '{{.Service}}|{{.State}}|{{.Health}}' 2>/dev/null \
|
|
807
|
+
| tr -d '\r' | awk -F'|' -v s="$_APP_RUNNER_WEB_SERVICE" '$1==s {print; exit}')
|
|
808
|
+
_web_state=$(printf '%s' "$_web_line" | awk -F'|' '{print $2}')
|
|
809
|
+
_web_health=$(printf '%s' "$_web_line" | awk -F'|' '{print $3}')
|
|
810
|
+
if [ "$_web_state" != "running" ]; then
|
|
811
|
+
# Container not running -> definitively down.
|
|
812
|
+
_write_health "false"
|
|
813
|
+
_write_app_state "crashed"
|
|
814
|
+
return 1
|
|
815
|
+
fi
|
|
816
|
+
if [ -n "$_web_health" ]; then
|
|
817
|
+
# A healthcheck is declared: it is authoritative.
|
|
818
|
+
if [ "$_web_health" = "healthy" ]; then
|
|
819
|
+
_write_health "true"
|
|
820
|
+
_write_app_state "running"
|
|
821
|
+
return 0
|
|
822
|
+
fi
|
|
823
|
+
if [ "$_web_health" = "unhealthy" ]; then
|
|
824
|
+
# Container up but failing its own healthcheck (not serving).
|
|
825
|
+
_write_health "false"
|
|
826
|
+
_write_app_state "crashed"
|
|
827
|
+
return 1
|
|
828
|
+
fi
|
|
829
|
+
# "starting" (within start_period): up, not yet healthy. Report
|
|
830
|
+
# running so the watchdog gives it time instead of restarting,
|
|
831
|
+
# but do not yet claim a passing health.
|
|
832
|
+
_write_health "false"
|
|
833
|
+
_write_app_state "running"
|
|
834
|
+
return 0
|
|
835
|
+
fi
|
|
836
|
+
# No healthcheck declared: container running is the signal.
|
|
698
837
|
_write_health "true"
|
|
699
838
|
_write_app_state "running"
|
|
700
839
|
return 0
|
|
701
|
-
else
|
|
702
|
-
_write_health "false"
|
|
703
|
-
return 1
|
|
704
840
|
fi
|
|
841
|
+
# No web service identified (legacy/degraded): fall back to the
|
|
842
|
+
# original "any container running" signal.
|
|
843
|
+
_write_health "true"
|
|
844
|
+
_write_app_state "running"
|
|
845
|
+
return 0
|
|
705
846
|
fi
|
|
706
847
|
|
|
707
848
|
# Check PID is alive (non-docker-compose methods)
|
|
@@ -769,6 +910,36 @@ app_runner_should_restart() {
|
|
|
769
910
|
app_runner_watchdog() {
|
|
770
911
|
_app_runner_dir
|
|
771
912
|
|
|
913
|
+
# v7.26.0 (Phase 4): docker compose runs detached (`up -d` exits immediately),
|
|
914
|
+
# so the captured PID is a short-lived subshell and `kill -0` is the wrong
|
|
915
|
+
# liveness signal for a compose stack. For compose, delegate to
|
|
916
|
+
# app_runner_health_check, whose compose branch keys on the primary web
|
|
917
|
+
# SERVICE container running (GAP #4) and writes health.json + state.json.
|
|
918
|
+
# This is what makes the service-aware health logic actually fire in the
|
|
919
|
+
# live monitoring loop (not just in isolation). On an unhealthy web service
|
|
920
|
+
# it restarts the stack under the same crash-count circuit breaker.
|
|
921
|
+
if [ "$_APP_RUNNER_IS_DOCKER" = true ] && echo "$_APP_RUNNER_METHOD" | grep -q "docker compose"; then
|
|
922
|
+
if app_runner_health_check; then
|
|
923
|
+
return 0
|
|
924
|
+
fi
|
|
925
|
+
_APP_RUNNER_CRASH_COUNT=$(( _APP_RUNNER_CRASH_COUNT + 1 ))
|
|
926
|
+
log_warn "App Runner: compose web service unhealthy (crash #$_APP_RUNNER_CRASH_COUNT)"
|
|
927
|
+
if [ "$_APP_RUNNER_CRASH_COUNT" -ge 5 ]; then
|
|
928
|
+
log_error "App Runner: crash limit reached (5), marking as crashed"
|
|
929
|
+
tail -20 "$_APP_RUNNER_DIR/app.log" 2>/dev/null | while IFS= read -r line; do
|
|
930
|
+
log_error " $line"
|
|
931
|
+
done
|
|
932
|
+
_write_app_state "crashed"
|
|
933
|
+
return 1
|
|
934
|
+
fi
|
|
935
|
+
local _c_backoff=$(( 1 << _APP_RUNNER_CRASH_COUNT ))
|
|
936
|
+
[ "$_c_backoff" -gt 30 ] && _c_backoff=30
|
|
937
|
+
log_info "App Runner: restarting compose stack in ${_c_backoff}s..."
|
|
938
|
+
sleep "$_c_backoff"
|
|
939
|
+
app_runner_start || log_warn "App Runner: compose auto-restart failed"
|
|
940
|
+
return 0
|
|
941
|
+
fi
|
|
942
|
+
|
|
772
943
|
if [ -z "$_APP_RUNNER_PID" ] && [ -f "$_APP_RUNNER_DIR/app.pid" ]; then
|
|
773
944
|
_APP_RUNNER_PID=$(cat "$_APP_RUNNER_DIR/app.pid" 2>/dev/null)
|
|
774
945
|
fi
|
package/autonomy/run.sh
CHANGED
|
@@ -10465,6 +10465,14 @@ build_prompt() {
|
|
|
10465
10465
|
# same precedent as AUTONOMY_OVERRIDE_TEXT in providers/claude_flags.ts).
|
|
10466
10466
|
local agents_md_instruction="Project conventions: read AGENTS.md in the repository root for build, test, and style conventions. If AGENTS.md is absent, read CLAUDE.md instead. The nearest such file to the code you are editing takes precedence."
|
|
10467
10467
|
|
|
10468
|
+
# Compose-first instruction (v7.26.0): unconditional string with conditional
|
|
10469
|
+
# phrasing (YOU decide whether the app warrants compose, not a static grep).
|
|
10470
|
+
# When an app needs more than one running service (web + database and/or
|
|
10471
|
+
# cache), a docker-compose.yml is the run contract Loki's app runner uses to
|
|
10472
|
+
# bring the whole stack up locally. This string MUST stay byte-identical to
|
|
10473
|
+
# COMPOSE_INSTRUCTION in loki-ts/src/runner/build_prompt.ts (parity-locked).
|
|
10474
|
+
local compose_instruction="RUN_CONTRACT: Decide whether this app needs more than one running service. If it needs a database (PostgreSQL/MySQL/MongoDB) and/or a cache (Redis) and/or separate backend and frontend services, generate a 12-factor docker-compose.yml at the project root so the whole stack runs with one command. Requirements when you generate it: (1) name the primary web/app service so it is obvious (service key 'web' or 'app', or add the label 'loki.primary=true' on it) and publish its HTTP port (host:container, e.g. '3000:3000'); (2) give every service a healthcheck (the web service must have an HTTP healthcheck so 'up' means actually serving, not just started); (3) wire dependencies with depends_on and config via environment variables; (4) write a .env.example listing every required variable with safe placeholder values; (5) keep secrets out of the compose file and out of git. If the app is a single service with no datastore, do NOT add compose; a plain run command is correct. If a working docker-compose.yml already exists and matches the app, leave it; otherwise create or update it. Verify the stack comes up (docker compose up) before claiming completion."
|
|
10475
|
+
|
|
10468
10476
|
# Load existing context if resuming
|
|
10469
10477
|
local context_injection=""
|
|
10470
10478
|
if [ $retry -gt 0 ]; then
|
|
@@ -10794,15 +10802,15 @@ except Exception:
|
|
|
10794
10802
|
else
|
|
10795
10803
|
if [ $retry -eq 0 ]; then
|
|
10796
10804
|
if [ -n "$prd" ]; then
|
|
10797
|
-
echo "Loki Mode with PRD at $prd. $update_instruction $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 $usage_doc_instruction $lsp_grounding_instruction $agents_md_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
10805
|
+
echo "Loki Mode with PRD at $prd. $update_instruction $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 $usage_doc_instruction $compose_instruction $lsp_grounding_instruction $agents_md_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
10798
10806
|
else
|
|
10799
|
-
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 $usage_doc_instruction $lsp_grounding_instruction $agents_md_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
10807
|
+
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 $usage_doc_instruction $compose_instruction $lsp_grounding_instruction $agents_md_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
10800
10808
|
fi
|
|
10801
10809
|
else
|
|
10802
10810
|
if [ -n "$prd" ]; then
|
|
10803
|
-
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 $usage_doc_instruction $lsp_grounding_instruction $agents_md_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
10811
|
+
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 $usage_doc_instruction $compose_instruction $lsp_grounding_instruction $agents_md_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
10804
10812
|
else
|
|
10805
|
-
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 $usage_doc_instruction $lsp_grounding_instruction $agents_md_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
10813
|
+
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 $usage_doc_instruction $compose_instruction $lsp_grounding_instruction $agents_md_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
|
|
10806
10814
|
fi
|
|
10807
10815
|
fi
|
|
10808
10816
|
fi
|
|
@@ -10844,6 +10852,7 @@ except Exception:
|
|
|
10844
10852
|
printf 'You are a coding assistant. Analyze this codebase and suggest improvements. Write working code and commit changes.\n'
|
|
10845
10853
|
fi
|
|
10846
10854
|
printf '%s\n' "$usage_doc_instruction"
|
|
10855
|
+
printf '%s\n' "$compose_instruction"
|
|
10847
10856
|
printf '%s\n' "$lsp_grounding_instruction"
|
|
10848
10857
|
printf '%s\n' "$agents_md_instruction"
|
|
10849
10858
|
printf '</loki_system>\n'
|
|
@@ -10877,6 +10886,7 @@ except Exception:
|
|
|
10877
10886
|
printf '%s\n' "$autonomous_suffix"
|
|
10878
10887
|
printf '%s\n' "$memory_instruction"
|
|
10879
10888
|
printf '%s\n' "$usage_doc_instruction"
|
|
10889
|
+
printf '%s\n' "$compose_instruction"
|
|
10880
10890
|
printf '%s\n' "$lsp_grounding_instruction"
|
|
10881
10891
|
printf '%s\n' "$agents_md_instruction"
|
|
10882
10892
|
# For codebase-analysis mode (no PRD), analysis_instruction is part of the
|
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.26.0
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var f8=Object.defineProperty;var u8=($)=>$;function c8($,Q){this[$]=u8.bind(null,Q)}var g=($,Q)=>{for(var Z in Q)f8($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:c8.bind(Q,Z)})};var k=($,Q)=>()=>($&&(Q=$($=0)),Q);var X1=import.meta.require;var F$={};g(F$,{lokiDir:()=>P,homeLokiDir:()=>o1,findRepoRootForVersion:()=>d1,REPO_ROOT:()=>f});import{resolve as n,dirname as l1}from"path";import{fileURLToPath as p8}from"url";import{existsSync as L1}from"fs";import{homedir as l8}from"os";function d8(){let $=j$;for(let Q=0;Q<6;Q++){if(L1(n($,"VERSION"))&&L1(n($,"autonomy/run.sh")))return $;let Z=l1($);if(Z===$)break;$=Z}return n(j$,"..","..","..")}function d1($){let Q=$;for(let Z=0;Z<6;Z++){if(L1(n(Q,"VERSION"))&&L1(n(Q,"autonomy/run.sh")))return Q;let z=l1(Q);if(z===Q)break;Q=z}return n($,"..","..","..")}function P(){return process.env.LOKI_DIR??n(process.cwd(),".loki")}function o1(){return n(l8(),".loki")}var j$,f;var y=k(()=>{j$=l1(p8(import.meta.url));f=d8()});import{readFileSync as o8}from"fs";import{resolve as n8,dirname as a8}from"path";import{fileURLToPath as s8}from"url";function k1(){if($1!==null)return $1;let $="7.
|
|
2
|
+
var f8=Object.defineProperty;var u8=($)=>$;function c8($,Q){this[$]=u8.bind(null,Q)}var g=($,Q)=>{for(var Z in Q)f8($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:c8.bind(Q,Z)})};var k=($,Q)=>()=>($&&(Q=$($=0)),Q);var X1=import.meta.require;var F$={};g(F$,{lokiDir:()=>P,homeLokiDir:()=>o1,findRepoRootForVersion:()=>d1,REPO_ROOT:()=>f});import{resolve as n,dirname as l1}from"path";import{fileURLToPath as p8}from"url";import{existsSync as L1}from"fs";import{homedir as l8}from"os";function d8(){let $=j$;for(let Q=0;Q<6;Q++){if(L1(n($,"VERSION"))&&L1(n($,"autonomy/run.sh")))return $;let Z=l1($);if(Z===$)break;$=Z}return n(j$,"..","..","..")}function d1($){let Q=$;for(let Z=0;Z<6;Z++){if(L1(n(Q,"VERSION"))&&L1(n(Q,"autonomy/run.sh")))return Q;let z=l1(Q);if(z===Q)break;Q=z}return n($,"..","..","..")}function P(){return process.env.LOKI_DIR??n(process.cwd(),".loki")}function o1(){return n(l8(),".loki")}var j$,f;var y=k(()=>{j$=l1(p8(import.meta.url));f=d8()});import{readFileSync as o8}from"fs";import{resolve as n8,dirname as a8}from"path";import{fileURLToPath as s8}from"url";function k1(){if($1!==null)return $1;let $="7.26.0";if(typeof $==="string"&&$.length>0)return $1=$,$1;try{let Q=a8(s8(import.meta.url)),Z=d1(Q);$1=o8(n8(Z,"VERSION"),"utf-8").trim()}catch{$1="unknown"}return $1}var $1=null;var n1=k(()=>{y()});var E$={};g(E$,{runOrThrow:()=>t8,run:()=>j,commandVersion:()=>i8,commandExists:()=>v,ShellError:()=>a1});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,K;if(Q.timeoutMs&&Q.timeoutMs>0)z=setTimeout(()=>{try{Z.kill("SIGTERM")}catch{}K=setTimeout(()=>{try{Z.kill("SIGKILL")}catch{}},2000)},Q.timeoutMs);try{let[H,X,q]=await Promise.all([new Response(Z.stdout).text(),new Response(Z.stderr).text(),Z.exited]);return{stdout:H,stderr:X,exitCode:q}}finally{if(z)clearTimeout(z);if(K)clearTimeout(K)}}async function t8($,Q={}){let Z=await j($,Q);if(Z.exitCode!==0)throw new a1(`command failed (${Z.exitCode}): ${$.join(" ")}`,Z.exitCode,Z.stdout,Z.stderr);return Z}async function v($){let Q=r8($),Z=await j(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function r8($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function i8($,Q="--version"){if(!await v($))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 a1;var d=k(()=>{a1=class a1 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 e8?"":$}var e8,T,N,_,KZ,A,R,h,J;var c=k(()=>{e8=(process.env.NO_COLOR??"").length>0;T=a("\x1B[0;31m"),N=a("\x1B[0;32m"),_=a("\x1B[1;33m"),KZ=a("\x1B[0;34m"),A=a("\x1B[0;36m"),R=a("\x1B[1m"),h=a("\x1B[2m"),J=a("\x1B[0m")});import{existsSync as U7}from"fs";async function Q1(){if(B1!==void 0)return B1;let $="/opt/homebrew/bin/python3.12";if(U7($))return B1=$,$;let Q=await v("python3.12");if(Q)return B1=Q,Q;let Z=await v("python3");return B1=Z,Z}async function Z1($,Q={}){let Z=await Q1();if(!Z)return{stdout:"",stderr:"python3 not found",exitCode:127};return j([Z,"-c",$],Q)}var B1;var H1=k(()=>{d()});var d$={};g(d$,{runStatus:()=>N7});import{existsSync as b,readFileSync as q1,readdirSync as v$,statSync as f$}from"fs";import{resolve as D,basename as P7}from"path";import{homedir as L7}from"os";async function j7(){if(await v("jq"))return!0;return process.stdout.write(`${T}Error: jq is required but not installed.${J}
|
|
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)
|
|
@@ -787,4 +787,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
787
787
|
`),2}default:return process.stderr.write(`Unknown command: ${Q}
|
|
788
788
|
`),process.stderr.write(v8),2}}g$();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var l3=await p3(Bun.argv.slice(2));process.exit(l3);
|
|
789
789
|
|
|
790
|
-
//# debugId=
|
|
790
|
+
//# debugId=7BD97DA7996A924D64756E2164756E21
|
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loki-mode",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.26.0",
|
|
4
4
|
"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).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|