loki-mode 5.52.0 → 5.52.1

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 CHANGED
@@ -473,60 +473,8 @@ Go get coffee. It'll be deployed when you get back.
473
473
 
474
474
  ## Architecture
475
475
 
476
- ```mermaid
477
- graph TB
478
- PRD["PRD Document"] --> REASON
479
-
480
- subgraph RARVC["RARV+C Cycle"]
481
- direction TB
482
- REASON["1. Reason"] --> ACT["2. Act"]
483
- ACT --> REFLECT["3. Reflect"]
484
- REFLECT --> VERIFY["4. Verify"]
485
- VERIFY -->|"pass"| COMPOUND["5. Compound"]
486
- VERIFY -->|"fail"| REASON
487
- COMPOUND --> REASON
488
- end
489
-
490
- subgraph PROVIDERS["Provider Layer"]
491
- CLAUDE["Claude Code<br/>(full features)"]
492
- CODEX["Codex CLI<br/>(degraded)"]
493
- GEMINI["Gemini CLI<br/>(degraded)"]
494
- end
495
-
496
- ACT --> PROVIDERS
497
-
498
- subgraph AGENTS["Agent Swarms (41 types)"]
499
- ENG["Engineering (8)"]
500
- OPS["Operations (8)"]
501
- BIZ["Business (8)"]
502
- DATA["Data (3)"]
503
- PROD["Product (3)"]
504
- GROWTH["Growth (4)"]
505
- REVIEW["Review (3)"]
506
- ORCH["Orchestration (4)"]
507
- end
508
-
509
- PROVIDERS --> AGENTS
510
-
511
- subgraph INFRA["Infrastructure"]
512
- DASHBOARD["Dashboard<br/>(FastAPI + Web UI)<br/>TLS/HTTPS, OIDC, RBAC"]
513
- MEMORY["Memory System<br/>(Episodic/Semantic/Procedural)"]
514
- COUNCIL["Completion Council<br/>(3-member voting)"]
515
- QUEUE["Task Queue<br/>(.loki/queue/)"]
516
- METRICS["Metrics Export<br/>(Prometheus/OpenMetrics)"]
517
- AUDIT["Audit Trail<br/>(SHA-256 integrity chain)"]
518
- end
519
-
520
- AGENTS --> QUEUE
521
- VERIFY --> COUNCIL
522
- REFLECT --> MEMORY
523
- COMPOUND --> MEMORY
524
- AGENTS --> AUDIT
525
- DASHBOARD -.->|"reads"| QUEUE
526
- DASHBOARD -.->|"reads"| MEMORY
527
- DASHBOARD -.->|"reads"| AUDIT
528
- DASHBOARD -.->|"exposes"| METRICS
529
- ```
476
+ <img width="6961" height="6302" alt="architecture" src="https://github.com/user-attachments/assets/d9954dd2-5cb6-4b1c-8cd2-67f68141dffa" />
477
+
530
478
 
531
479
  **Key components:**
532
480
  - **RARV+C Cycle** -- Reason, Act, Reflect, Verify, Compound. Every iteration follows this loop. Failed verification triggers retry from Reason.
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 v5.52.0
6
+ # Loki Mode v5.52.1
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -263,4 +263,4 @@ The following features are documented in skill modules but not yet fully automat
263
263
  | Quality gates 3-reviewer system | Implemented (v5.35.0) | 5 specialist reviewers in `skills/quality-gates.md`; execution in run.sh |
264
264
  | Benchmarks (HumanEval, SWE-bench) | Infrastructure only | Runner scripts and datasets exist in `benchmarks/`; no published results |
265
265
 
266
- **v5.52.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
266
+ **v5.52.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 5.52.0
1
+ 5.52.1
@@ -39,6 +39,9 @@ BLOCKED_PATTERNS=(
39
39
  "rm .*\.loki/session\.lock"
40
40
  "> \.loki/council/"
41
41
  "> \.loki/config\.yaml"
42
+ # Fork bomb patterns
43
+ ":\(\)\{.*\|.*&"
44
+ ":\(\) *\{.*\|.*&"
42
45
  )
43
46
 
44
47
  # Safe path patterns that override blocked pattern matches
@@ -59,7 +62,7 @@ for pattern in "${BLOCKED_PATTERNS[@]}"; do
59
62
  fi
60
63
  done
61
64
  "$is_safe" && continue
62
- printf '%s' '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Blocked: potentially dangerous command pattern detected"}}'
65
+ printf '%s' '{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "Blocked: potentially dangerous command pattern detected"}}'
63
66
  exit 2
64
67
  fi
65
68
  done
@@ -71,6 +74,6 @@ printf '%s' "{\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"command\":$(ech
71
74
  echo >> "$LOG_DIR/bash-audit.jsonl"
72
75
 
73
76
  # Allow command
74
- printf '%s' '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
77
+ printf '%s' '{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "allow"}}'
75
78
 
76
79
  exit 0
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "5.52.0"
10
+ __version__ = "5.52.1"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -46,7 +46,7 @@ from .models import (
46
46
  from . import registry
47
47
  from . import auth
48
48
  from . import audit
49
- from . import secrets as secrets_mod
49
+ from . import app_secrets as secrets_mod
50
50
  from . import telemetry as _telemetry
51
51
  from .control import atomic_write_json
52
52
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  The flagship product of [Autonomi](https://www.autonomi.dev/). Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v5.52.0
5
+ **Version:** v5.52.1
6
6
 
7
7
  ---
8
8
 
package/mcp/__init__.py CHANGED
@@ -21,4 +21,4 @@ try:
21
21
  except ImportError:
22
22
  __all__ = ['mcp']
23
23
 
24
- __version__ = '5.52.0'
24
+ __version__ = '5.52.1'
package/mcp/server.py CHANGED
@@ -979,6 +979,236 @@ async def get_pending_tasks() -> str:
979
979
  return json.dumps({"error": "Access denied", "pending_tasks": [], "count": 0})
980
980
 
981
981
 
982
+ # ============================================================
983
+ # ENTERPRISE TOOLS (P0-1)
984
+ # ============================================================
985
+
986
+ @mcp.tool()
987
+ async def loki_start_project(prd_content: str = "", prd_path: str = "") -> str:
988
+ """
989
+ Start a new Loki Mode project from a PRD.
990
+
991
+ Args:
992
+ prd_content: Inline PRD content (takes priority over prd_path)
993
+ prd_path: Path to a PRD file on disk
994
+
995
+ Returns:
996
+ JSON with project initialization status
997
+ """
998
+ _emit_tool_event_async('loki_start_project', 'start', parameters={'prd_path': prd_path})
999
+ try:
1000
+ content = prd_content
1001
+ if not content and prd_path:
1002
+ resolved = safe_path_join('.', prd_path)
1003
+ if os.path.exists(resolved):
1004
+ with safe_open(resolved, 'r') as f:
1005
+ content = f.read()
1006
+ else:
1007
+ return json.dumps({"error": f"PRD file not found: {prd_path}"})
1008
+
1009
+ if not content:
1010
+ return json.dumps({"error": "No PRD content or path provided"})
1011
+
1012
+ # Initialize project state
1013
+ os.makedirs('.loki/state', exist_ok=True)
1014
+ project = {
1015
+ "status": "initialized",
1016
+ "prd_length": len(content),
1017
+ "prd_path": prd_path or "inline",
1018
+ "created_at": datetime.now(timezone.utc).isoformat(),
1019
+ }
1020
+ state_path = safe_path_join('.loki', 'state', 'project.json')
1021
+ with safe_open(state_path, 'w') as f:
1022
+ json.dump(project, f, indent=2)
1023
+
1024
+ _emit_tool_event_async('loki_start_project', 'complete', result_status='success')
1025
+ return json.dumps({"success": True, **project})
1026
+ except PathTraversalError as e:
1027
+ return json.dumps({"error": f"Access denied: {e}"})
1028
+ except Exception as e:
1029
+ logger.error(f"Start project failed: {e}")
1030
+ _emit_tool_event_async('loki_start_project', 'complete', result_status='error', error=str(e))
1031
+ return json.dumps({"error": str(e)})
1032
+
1033
+
1034
+ @mcp.tool()
1035
+ async def loki_project_status() -> str:
1036
+ """
1037
+ Get the current project status including RARV cycle state, agent activity, and task progress.
1038
+
1039
+ Returns:
1040
+ JSON with project status, phase, iteration, agents, and task counts
1041
+ """
1042
+ _emit_tool_event_async('loki_project_status', 'start', parameters={})
1043
+ try:
1044
+ status = {}
1045
+
1046
+ # Read orchestrator state
1047
+ orch_path = safe_path_join('.loki', 'state', 'orchestrator.json')
1048
+ if os.path.exists(orch_path):
1049
+ with safe_open(orch_path, 'r') as f:
1050
+ status["orchestrator"] = json.load(f)
1051
+
1052
+ # Read project state
1053
+ proj_path = safe_path_join('.loki', 'state', 'project.json')
1054
+ if os.path.exists(proj_path):
1055
+ with safe_open(proj_path, 'r') as f:
1056
+ status["project"] = json.load(f)
1057
+
1058
+ # Read task queue summary
1059
+ queue_path = safe_path_join('.loki', 'state', 'task-queue.json')
1060
+ if os.path.exists(queue_path):
1061
+ with safe_open(queue_path, 'r') as f:
1062
+ queue = json.load(f)
1063
+ tasks = queue.get("tasks", [])
1064
+ status["tasks"] = {
1065
+ "total": len(tasks),
1066
+ "pending": sum(1 for t in tasks if t.get("status") == "pending"),
1067
+ "in_progress": sum(1 for t in tasks if t.get("status") == "in-progress"),
1068
+ "completed": sum(1 for t in tasks if t.get("status") == "completed"),
1069
+ }
1070
+
1071
+ if not status:
1072
+ status = {"status": "no_project", "message": "No active project found"}
1073
+
1074
+ _emit_tool_event_async('loki_project_status', 'complete', result_status='success')
1075
+ return json.dumps(status, default=str)
1076
+ except PathTraversalError:
1077
+ return json.dumps({"error": "Access denied"})
1078
+ except Exception as e:
1079
+ logger.error(f"Project status failed: {e}")
1080
+ _emit_tool_event_async('loki_project_status', 'complete', result_status='error', error=str(e))
1081
+ return json.dumps({"error": str(e)})
1082
+
1083
+
1084
+ @mcp.tool()
1085
+ async def loki_agent_metrics() -> str:
1086
+ """
1087
+ Get agent metrics including token usage, task completion rates, and timing.
1088
+
1089
+ Returns:
1090
+ JSON with per-agent metrics and aggregates
1091
+ """
1092
+ _emit_tool_event_async('loki_agent_metrics', 'start', parameters={})
1093
+ try:
1094
+ metrics = {"agents": [], "aggregate": {}}
1095
+
1096
+ # Read efficiency metrics
1097
+ metrics_dir = safe_path_join('.loki', 'metrics', 'efficiency')
1098
+ if os.path.isdir(metrics_dir):
1099
+ for fname in os.listdir(metrics_dir):
1100
+ if fname.endswith('.json'):
1101
+ fpath = os.path.join(metrics_dir, fname)
1102
+ with open(fpath, 'r') as f:
1103
+ metrics["agents"].append(json.load(f))
1104
+
1105
+ # Read token economics
1106
+ econ_path = safe_path_join('.loki', 'metrics', 'token-economics.json')
1107
+ if os.path.exists(econ_path):
1108
+ with safe_open(econ_path, 'r') as f:
1109
+ metrics["token_economics"] = json.load(f)
1110
+
1111
+ metrics["agent_count"] = len(metrics["agents"])
1112
+ _emit_tool_event_async('loki_agent_metrics', 'complete', result_status='success')
1113
+ return json.dumps(metrics, default=str)
1114
+ except PathTraversalError:
1115
+ return json.dumps({"error": "Access denied"})
1116
+ except Exception as e:
1117
+ logger.error(f"Agent metrics failed: {e}")
1118
+ _emit_tool_event_async('loki_agent_metrics', 'complete', result_status='error', error=str(e))
1119
+ return json.dumps({"error": str(e)})
1120
+
1121
+
1122
+ @mcp.tool()
1123
+ async def loki_checkpoint_restore(checkpoint_id: str = "") -> str:
1124
+ """
1125
+ List available checkpoints or restore project state from a specific checkpoint.
1126
+
1127
+ Args:
1128
+ checkpoint_id: ID of checkpoint to restore (empty = list all)
1129
+
1130
+ Returns:
1131
+ JSON with available checkpoints or restoration result
1132
+ """
1133
+ _emit_tool_event_async('loki_checkpoint_restore', 'start', parameters={'checkpoint_id': checkpoint_id})
1134
+ try:
1135
+ cp_dir = safe_path_join('.loki', 'state', 'checkpoints')
1136
+ if not os.path.isdir(cp_dir):
1137
+ return json.dumps({"checkpoints": [], "message": "No checkpoints directory"})
1138
+
1139
+ checkpoints = []
1140
+ for fname in sorted(os.listdir(cp_dir)):
1141
+ if fname.endswith('.json'):
1142
+ fpath = os.path.join(cp_dir, fname)
1143
+ with open(fpath, 'r') as f:
1144
+ cp = json.load(f)
1145
+ cp["id"] = fname.replace('.json', '')
1146
+ checkpoints.append(cp)
1147
+
1148
+ if not checkpoint_id:
1149
+ _emit_tool_event_async('loki_checkpoint_restore', 'complete', result_status='success')
1150
+ return json.dumps({"checkpoints": checkpoints, "count": len(checkpoints)})
1151
+
1152
+ # Find and restore specific checkpoint
1153
+ target = next((c for c in checkpoints if c["id"] == checkpoint_id), None)
1154
+ if not target:
1155
+ return json.dumps({"error": f"Checkpoint not found: {checkpoint_id}"})
1156
+
1157
+ # Write checkpoint state as current state
1158
+ state_path = safe_path_join('.loki', 'state', 'orchestrator.json')
1159
+ with safe_open(state_path, 'w') as f:
1160
+ json.dump(target, f, indent=2)
1161
+
1162
+ _emit_tool_event_async('loki_checkpoint_restore', 'complete', result_status='success')
1163
+ return json.dumps({"restored": True, "checkpoint_id": checkpoint_id})
1164
+ except PathTraversalError:
1165
+ return json.dumps({"error": "Access denied"})
1166
+ except Exception as e:
1167
+ logger.error(f"Checkpoint restore failed: {e}")
1168
+ _emit_tool_event_async('loki_checkpoint_restore', 'complete', result_status='error', error=str(e))
1169
+ return json.dumps({"error": str(e)})
1170
+
1171
+
1172
+ @mcp.tool()
1173
+ async def loki_quality_report() -> str:
1174
+ """
1175
+ Get quality gate results including blind review scores, council verdicts, and test coverage.
1176
+
1177
+ Returns:
1178
+ JSON with quality gate status, review results, and coverage metrics
1179
+ """
1180
+ _emit_tool_event_async('loki_quality_report', 'start', parameters={})
1181
+ try:
1182
+ report = {"gates": [], "council": None, "coverage": None}
1183
+
1184
+ # Read quality gate results
1185
+ gates_path = safe_path_join('.loki', 'state', 'quality-gates.json')
1186
+ if os.path.exists(gates_path):
1187
+ with safe_open(gates_path, 'r') as f:
1188
+ report["gates"] = json.load(f)
1189
+
1190
+ # Read council results
1191
+ council_path = safe_path_join('.loki', 'state', 'council-results.json')
1192
+ if os.path.exists(council_path):
1193
+ with safe_open(council_path, 'r') as f:
1194
+ report["council"] = json.load(f)
1195
+
1196
+ # Read coverage
1197
+ coverage_path = safe_path_join('.loki', 'metrics', 'coverage.json')
1198
+ if os.path.exists(coverage_path):
1199
+ with safe_open(coverage_path, 'r') as f:
1200
+ report["coverage"] = json.load(f)
1201
+
1202
+ _emit_tool_event_async('loki_quality_report', 'complete', result_status='success')
1203
+ return json.dumps(report, default=str)
1204
+ except PathTraversalError:
1205
+ return json.dumps({"error": "Access denied"})
1206
+ except Exception as e:
1207
+ logger.error(f"Quality report failed: {e}")
1208
+ _emit_tool_event_async('loki_quality_report', 'complete', result_status='error', error=str(e))
1209
+ return json.dumps({"error": str(e)})
1210
+
1211
+
982
1212
  # ============================================================
983
1213
  # PROMPTS - Pre-built prompt templates
984
1214
  # ============================================================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "5.52.0",
3
+ "version": "5.52.1",
4
4
  "description": "Loki Mode by Autonomi - Multi-agent autonomous startup system for Claude Code, Codex CLI, and Gemini CLI",
5
5
  "keywords": [
6
6
  "autonomi",
File without changes