loki-mode 7.23.0 → 7.24.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 +4 -2
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +85 -0
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +79 -2
- package/dashboard/static/index.html +224 -121
- package/docs/COMPETITIVE-ANALYSIS-INSTANT-PREVIEW-2026-06.md +114 -0
- 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
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
|
|
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
|
+
- **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).
|
|
29
30
|
- **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`)
|
|
30
31
|
- **Self-hosted and private** -- Your keys, your infrastructure, no data leaves your network
|
|
31
32
|
- **Legacy system healing** -- `loki heal` archaeology/stabilize/isolate/modernize/validate phases (v6.67.0, see `skills/healing.md`)
|
|
@@ -251,7 +252,7 @@ Blind review, anti-sycophancy, severity blocking, mock/mutation detection, backw
|
|
|
251
252
|
<td width="33%" valign="top">
|
|
252
253
|
|
|
253
254
|
### Dashboard
|
|
254
|
-
Real-time monitoring, agent status, task queue, WebSocket streaming. Auto-starts at `localhost:57374`.
|
|
255
|
+
Real-time monitoring, agent status, task queue, WebSocket streaming, and Live App Preview (embedded iframe of the running app with Refresh/Open/Restart toolbar). Auto-starts at `localhost:57374`.
|
|
255
256
|
|
|
256
257
|
[Dashboard Guide](docs/dashboard-guide.md)
|
|
257
258
|
|
|
@@ -352,6 +353,7 @@ Claude gets full features (subagents, parallelization, MCP, Task tool). Other ac
|
|
|
352
353
|
| `loki pause` / `resume` | Pause/resume after current session |
|
|
353
354
|
| `loki status` | Show current status |
|
|
354
355
|
| `loki dashboard` | Open web dashboard |
|
|
356
|
+
| `loki preview` / `loki open` | Print running app URL and open in browser (Live App Preview, v7.24.0) |
|
|
355
357
|
| `loki web` | Launch Purple Lab web UI |
|
|
356
358
|
| `loki doctor` | Check environment and dependencies |
|
|
357
359
|
| `loki plan [PRD]` | Pre-execution analysis: complexity, cost, iterations |
|
|
@@ -421,7 +423,7 @@ See [benchmarks/](benchmarks/) for methodology.
|
|
|
421
423
|
|
|
422
424
|

|
|
423
425
|
|
|
424
|
-
*
|
|
426
|
+
*11 slides: Problem, Solution, 41 Agents, RARV Cycle, 9 Quality Gates (HumanEval 98.78%), Multi-Provider, Enterprise Hardening (Live App Preview), Full Lifecycle*
|
|
425
427
|
|
|
426
428
|
**[Download PPTX](docs/loki-mode-presentation.pptx)**
|
|
427
429
|
|
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.24.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.24.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
7.
|
|
1
|
+
7.24.0
|
package/autonomy/loki
CHANGED
|
@@ -536,6 +536,7 @@ show_help() {
|
|
|
536
536
|
echo " logs Show recent log output"
|
|
537
537
|
echo " dashboard [cmd] Dashboard server (start|stop|status|url|open)"
|
|
538
538
|
echo " web [cmd] Web app UI (start|stop|status) -- serves web-app/dist/"
|
|
539
|
+
echo " preview Open the running app Loki built (alias: open)"
|
|
539
540
|
echo " provider [cmd] Manage AI provider (show|set|list|info)"
|
|
540
541
|
echo " serve Start dashboard/API server (alias for api start)"
|
|
541
542
|
echo " api [cmd] Dashboard/API server (start|stop|status)"
|
|
@@ -4751,6 +4752,87 @@ cmd_web_status() {
|
|
|
4751
4752
|
echo "Purple Lab is not running."
|
|
4752
4753
|
}
|
|
4753
4754
|
|
|
4755
|
+
# Open the running app preview (the app Loki built and started locally).
|
|
4756
|
+
# Surfaces the existing app-runner state; does not start or change the app.
|
|
4757
|
+
cmd_preview() {
|
|
4758
|
+
local open_browser=true
|
|
4759
|
+
case "${1:-}" in
|
|
4760
|
+
--help|-h|help)
|
|
4761
|
+
echo -e "${BOLD}Loki Mode -- open the running app preview${NC}"
|
|
4762
|
+
echo ""
|
|
4763
|
+
echo "Usage: loki preview [--no-open]"
|
|
4764
|
+
echo " loki open (alias)"
|
|
4765
|
+
echo ""
|
|
4766
|
+
echo "Prints the URL of the app Loki built and started locally, then"
|
|
4767
|
+
echo "opens it in your browser. The app runner starts the app after the"
|
|
4768
|
+
echo "first successful build iteration. This serves a real local build"
|
|
4769
|
+
echo "from localhost on your machine; it is not hosted."
|
|
4770
|
+
echo ""
|
|
4771
|
+
echo "Options:"
|
|
4772
|
+
echo " --no-open Print the URL and status only; do not open a browser"
|
|
4773
|
+
echo " --help, -h Show this help and exit"
|
|
4774
|
+
return 0
|
|
4775
|
+
;;
|
|
4776
|
+
--no-open)
|
|
4777
|
+
open_browser=false
|
|
4778
|
+
;;
|
|
4779
|
+
esac
|
|
4780
|
+
|
|
4781
|
+
local state_file="${LOKI_DIR}/app-runner/state.json"
|
|
4782
|
+
if [ ! -f "$state_file" ]; then
|
|
4783
|
+
echo "No app running. The app runner starts after the first successful build iteration."
|
|
4784
|
+
echo "Run 'loki status' to check the current run."
|
|
4785
|
+
return 0
|
|
4786
|
+
fi
|
|
4787
|
+
|
|
4788
|
+
# Parse url/status/port. Prefer python3 (used throughout); fall back to grep.
|
|
4789
|
+
# Pass the path as argv (not inline interpolation) so a path with quotes
|
|
4790
|
+
# cannot break the script, and parse all three fields in one invocation.
|
|
4791
|
+
local url status port parsed
|
|
4792
|
+
if command -v python3 &> /dev/null; then
|
|
4793
|
+
parsed=$(python3 -c "import json,sys
|
|
4794
|
+
try:
|
|
4795
|
+
d=json.load(open(sys.argv[1]))
|
|
4796
|
+
print(d.get('url',''))
|
|
4797
|
+
print(d.get('status',''))
|
|
4798
|
+
print(d.get('port',''))
|
|
4799
|
+
except Exception:
|
|
4800
|
+
print('');print('');print('')" "$state_file" 2>/dev/null)
|
|
4801
|
+
url=$(printf '%s\n' "$parsed" | sed -n '1p')
|
|
4802
|
+
status=$(printf '%s\n' "$parsed" | sed -n '2p')
|
|
4803
|
+
port=$(printf '%s\n' "$parsed" | sed -n '3p')
|
|
4804
|
+
else
|
|
4805
|
+
url=$(grep -oE '"url"[[:space:]]*:[[:space:]]*"[^"]*"' "$state_file" 2>/dev/null | head -1 | sed 's/.*"url"[[:space:]]*:[[:space:]]*"//;s/"$//')
|
|
4806
|
+
status=$(grep -oE '"status"[[:space:]]*:[[:space:]]*"[^"]*"' "$state_file" 2>/dev/null | head -1 | sed 's/.*"status"[[:space:]]*:[[:space:]]*"//;s/"$//')
|
|
4807
|
+
port=$(grep -oE '"port"[[:space:]]*:[[:space:]]*[0-9]+' "$state_file" 2>/dev/null | head -1 | grep -oE '[0-9]+$')
|
|
4808
|
+
fi
|
|
4809
|
+
|
|
4810
|
+
if [ "$status" != "running" ]; then
|
|
4811
|
+
echo "App is not running (status: ${status:-unknown})."
|
|
4812
|
+
echo "The app runner starts the app after a successful build iteration."
|
|
4813
|
+
return 0
|
|
4814
|
+
fi
|
|
4815
|
+
|
|
4816
|
+
if [ -z "$url" ]; then
|
|
4817
|
+
url="http://localhost:${port:-3000}"
|
|
4818
|
+
fi
|
|
4819
|
+
|
|
4820
|
+
echo -e "${GREEN}Live app:${NC} $url [running, port ${port:-?}]"
|
|
4821
|
+
echo "Served from localhost on this machine."
|
|
4822
|
+
|
|
4823
|
+
if [ "$open_browser" = true ]; then
|
|
4824
|
+
if command -v open &> /dev/null; then
|
|
4825
|
+
open "$url"
|
|
4826
|
+
elif command -v xdg-open &> /dev/null; then
|
|
4827
|
+
xdg-open "$url"
|
|
4828
|
+
elif command -v start &> /dev/null; then
|
|
4829
|
+
start "$url"
|
|
4830
|
+
else
|
|
4831
|
+
echo "Please open in browser: $url"
|
|
4832
|
+
fi
|
|
4833
|
+
fi
|
|
4834
|
+
}
|
|
4835
|
+
|
|
4754
4836
|
# Import GitHub issues
|
|
4755
4837
|
cmd_import() {
|
|
4756
4838
|
# v7.6.2 B-13 fix: --help must print help, not start an import.
|
|
@@ -13296,6 +13378,9 @@ main() {
|
|
|
13296
13378
|
web)
|
|
13297
13379
|
cmd_web "$@"
|
|
13298
13380
|
;;
|
|
13381
|
+
preview|open)
|
|
13382
|
+
cmd_preview "$@"
|
|
13383
|
+
;;
|
|
13299
13384
|
logs)
|
|
13300
13385
|
cmd_logs "$@"
|
|
13301
13386
|
;;
|
package/dashboard/__init__.py
CHANGED
package/dashboard/server.py
CHANGED
|
@@ -6628,20 +6628,97 @@ async def get_app_runner_status():
|
|
|
6628
6628
|
return {"status": "error"}
|
|
6629
6629
|
|
|
6630
6630
|
|
|
6631
|
+
def _get_log_redactor():
|
|
6632
|
+
"""Lazily load autonomy/lib/proof_redact.redact_value.
|
|
6633
|
+
|
|
6634
|
+
Lives under autonomy/lib (not on the dashboard import path), so import it
|
|
6635
|
+
by path with a graceful fallback. Returns a callable str -> str. On any
|
|
6636
|
+
import failure returns a redactor that withholds the line rather than
|
|
6637
|
+
leaking raw runtime output (which can contain secrets in stack traces).
|
|
6638
|
+
"""
|
|
6639
|
+
cached = getattr(_get_log_redactor, "_cached", None)
|
|
6640
|
+
if cached is not None:
|
|
6641
|
+
return cached
|
|
6642
|
+
try:
|
|
6643
|
+
import importlib.util
|
|
6644
|
+
|
|
6645
|
+
lib_path = _Path(__file__).resolve().parent.parent / "autonomy" / "lib" / "proof_redact.py"
|
|
6646
|
+
spec = importlib.util.spec_from_file_location("loki_proof_redact", str(lib_path))
|
|
6647
|
+
if spec is None or spec.loader is None:
|
|
6648
|
+
raise ImportError("proof_redact spec unavailable")
|
|
6649
|
+
mod = importlib.util.module_from_spec(spec)
|
|
6650
|
+
spec.loader.exec_module(mod)
|
|
6651
|
+
try:
|
|
6652
|
+
mod.set_context(home=os.path.expanduser("~"), repo_root=str(_project_root()))
|
|
6653
|
+
except Exception:
|
|
6654
|
+
pass
|
|
6655
|
+
redactor = mod.redact_value
|
|
6656
|
+
except Exception:
|
|
6657
|
+
# Fail closed: withhold rather than leak raw log content.
|
|
6658
|
+
def redactor(_s):
|
|
6659
|
+
return "[log withheld: redactor unavailable]"
|
|
6660
|
+
_get_log_redactor._cached = redactor
|
|
6661
|
+
return redactor
|
|
6662
|
+
|
|
6663
|
+
|
|
6631
6664
|
@app.get("/api/app-runner/logs")
|
|
6632
6665
|
async def get_app_runner_logs(lines: int = Query(default=100, ge=1, le=1000)):
|
|
6633
|
-
"""Get last N lines of app runner logs."""
|
|
6666
|
+
"""Get last N lines of app runner logs (redacted)."""
|
|
6634
6667
|
loki_dir = _get_loki_dir()
|
|
6635
6668
|
log_file = loki_dir / "app-runner" / "app.log"
|
|
6636
6669
|
if not log_file.exists():
|
|
6637
6670
|
return {"lines": []}
|
|
6638
6671
|
try:
|
|
6672
|
+
redact = _get_log_redactor()
|
|
6639
6673
|
all_lines = _safe_read_text(log_file).splitlines()
|
|
6640
|
-
return {"lines": all_lines[-lines:]}
|
|
6674
|
+
return {"lines": [redact(ln) for ln in all_lines[-lines:]], "redacted": True}
|
|
6641
6675
|
except OSError:
|
|
6642
6676
|
return {"lines": []}
|
|
6643
6677
|
|
|
6644
6678
|
|
|
6679
|
+
@app.get("/api/app-runner/errors")
|
|
6680
|
+
async def get_app_runner_errors(lines: int = Query(default=50, ge=1, le=500)):
|
|
6681
|
+
"""Get the last N lines of app runner output, redacted, plus crash state.
|
|
6682
|
+
|
|
6683
|
+
Powers the dashboard error banner. Reads .loki/app-runner/app.log (the same
|
|
6684
|
+
log the app writes) and the crash/status fields from state.json so the UI
|
|
6685
|
+
can decide whether to surface the banner without a second round-trip.
|
|
6686
|
+
The error banner is fed exclusively by this server-side endpoint: the
|
|
6687
|
+
running app is cross-origin to the dashboard, so the browser cannot read
|
|
6688
|
+
runtime errors out of the preview iframe.
|
|
6689
|
+
"""
|
|
6690
|
+
loki_dir = _get_loki_dir()
|
|
6691
|
+
app_dir = loki_dir / "app-runner"
|
|
6692
|
+
log_file = app_dir / "app.log"
|
|
6693
|
+
state_file = app_dir / "state.json"
|
|
6694
|
+
|
|
6695
|
+
status = "not_initialized"
|
|
6696
|
+
crash_count = 0
|
|
6697
|
+
if state_file.exists():
|
|
6698
|
+
try:
|
|
6699
|
+
state = json.loads(state_file.read_text())
|
|
6700
|
+
status = state.get("status", "unknown")
|
|
6701
|
+
crash_count = int(state.get("crash_count", 0) or 0)
|
|
6702
|
+
except (json.JSONDecodeError, OSError, ValueError, TypeError):
|
|
6703
|
+
status = "error"
|
|
6704
|
+
|
|
6705
|
+
out_lines = []
|
|
6706
|
+
if log_file.exists():
|
|
6707
|
+
try:
|
|
6708
|
+
redact = _get_log_redactor()
|
|
6709
|
+
all_lines = _safe_read_text(log_file).splitlines()
|
|
6710
|
+
out_lines = [redact(ln) for ln in all_lines[-lines:]]
|
|
6711
|
+
except OSError:
|
|
6712
|
+
out_lines = []
|
|
6713
|
+
|
|
6714
|
+
return {
|
|
6715
|
+
"lines": out_lines,
|
|
6716
|
+
"redacted": True,
|
|
6717
|
+
"status": status,
|
|
6718
|
+
"crash_count": crash_count,
|
|
6719
|
+
}
|
|
6720
|
+
|
|
6721
|
+
|
|
6645
6722
|
@app.post("/api/control/app-restart", dependencies=[Depends(auth.require_scope("control"))])
|
|
6646
6723
|
async def control_app_restart(request: Request):
|
|
6647
6724
|
"""Signal app runner to restart the application."""
|