loki-mode 11.3.0 → 11.3.2

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.
Files changed (242) hide show
  1. package/README.md +68 -650
  2. package/SKILL.md +5 -5
  3. package/VERSION +1 -1
  4. package/autonomy/completion-council.sh +2 -2
  5. package/autonomy/context-tracker.py +4 -4
  6. package/autonomy/council-v2.sh +1 -1
  7. package/autonomy/grill.sh +1 -1
  8. package/autonomy/lib/done-recognition.sh +1 -1
  9. package/autonomy/lib/efficiency_cost.py +8 -0
  10. package/autonomy/lib/engine10-push.sh +22 -8
  11. package/autonomy/lib/prd-enrich.sh +1 -1
  12. package/autonomy/lib/voter-agents.sh +1 -1
  13. package/autonomy/loki +161 -105
  14. package/autonomy/run.sh +30 -18
  15. package/autonomy/sandbox.sh +1 -1
  16. package/autonomy/tui.sh +6 -5
  17. package/autonomy/verify.sh +1 -1
  18. package/bin/loki +195 -59
  19. package/completions/_loki +8 -0
  20. package/completions/loki.bash +3 -3
  21. package/dashboard/__init__.py +1 -1
  22. package/dashboard/server.py +47 -45
  23. package/docs/AGENT-CHANGE-RECEIPT.md +2 -2
  24. package/docs/ARCHITECTURE.md +337 -0
  25. package/docs/BRANDING.md +124 -0
  26. package/docs/CLI-REFERENCE.md +11 -1
  27. package/docs/COMPONENTS.md +447 -0
  28. package/docs/DEPLOYMENT.md +9 -9
  29. package/docs/DOCKER.md +469 -0
  30. package/docs/INSTALLATION.md +67 -1045
  31. package/docs/KNOWN-ISSUES.md +11 -35
  32. package/docs/OTEL-COLLECTOR.md +24 -0
  33. package/docs/ROUTING-EVIDENCE.md +32 -0
  34. package/docs/TESTING.md +161 -0
  35. package/docs/air-gapped.md +1 -2
  36. package/docs/alternative-installations.md +14 -24
  37. package/docs/architecture/DECISIONS.md +333 -0
  38. package/docs/audit-logging.md +7 -7
  39. package/docs/authentication.md +3 -3
  40. package/docs/authorization.md +1 -1
  41. package/docs/certification/04-production-deployment/lab.md +6 -6
  42. package/docs/certification/04-production-deployment/lesson.md +4 -4
  43. package/docs/certification/README.md +1 -1
  44. package/docs/control-plane-container.md +2 -2
  45. package/docs/dev/real-run.md +34 -0
  46. package/docs/dev/release-checklist.md +2 -2
  47. package/docs/environment-variables.md +1 -0
  48. package/docs/exit-codes.md +3 -3
  49. package/docs/git-workflow.md +3 -3
  50. package/docs/metrics.md +37 -55
  51. package/docs/network-security.md +1 -1
  52. package/docs/siem-integration.md +5 -5
  53. package/docs/spec-first-intent.md +28 -0
  54. package/docs/v10/CLI-MODERN.md +7 -3
  55. package/docs/v10/DECISIONS.md +59 -0
  56. package/docs/v10/DEPS.md +22 -22
  57. package/docs/v10/ENGINE.md +1 -1
  58. package/docs/v10/FAILURE-CLASSES.md +212 -1
  59. package/docs/v10/FOUNDER-QUEUE.md +1 -0
  60. package/docs/v10/GUARDS.md +31 -0
  61. package/docs/v10/GUIDE.md +7 -5
  62. package/docs/v10/LEGACY-REMOVAL.md +4 -6
  63. package/docs/v10/METRICS.md +14 -2
  64. package/docs/v10/MODERNIZE.md +1 -1
  65. package/docs/v10/OPERATING-MODEL.md +4 -3
  66. package/docs/v10/PROGRESS.md +35 -0
  67. package/docs/v11/COST-HALF.md +352 -0
  68. package/docs/v11/INTOTO-AGENT-CHANGE-PREDICATE.md +77 -0
  69. package/docs/v11/MARKET-SLICES.md +315 -0
  70. package/docs/v11/MCP-2026-07-28.md +55 -0
  71. package/docs/v11/REGISTRIES.md +730 -0
  72. package/docs/v11/VERIFY-PR-SANDBOX.md +41 -0
  73. package/loki-ts/data/model-pricing.json +52 -24
  74. package/loki-ts/dist/loki.js +1185 -945
  75. package/mcp/__init__.py +1 -1
  76. package/mcp/v10_tools.py +29 -0
  77. package/package.json +9 -11
  78. package/packages/control-plane/dist/ask-tools-server.js +8 -2
  79. package/packages/control-plane/dist/server.js +15832 -12361
  80. package/packages/control-plane/drizzle/0006_token_sessions.sql +1 -0
  81. package/packages/control-plane/drizzle/meta/0006_snapshot.json +807 -0
  82. package/packages/control-plane/drizzle/meta/_journal.json +7 -0
  83. package/packages/control-plane/src/db/schema.ts +1 -0
  84. package/packages/control-plane/src/server/routes/cost.ts +4 -3
  85. package/packages/control-plane/src/server/runs.ts +3 -3
  86. package/packages/control-plane/ui/dist/assets/index-DbLzr87u.js +190 -0
  87. package/packages/control-plane/ui/dist/index.html +1 -1
  88. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  89. package/providers/opencode.sh +2 -3
  90. package/src/observability/genai-spans.js +104 -0
  91. package/src/observability/otel-bridge.js +49 -1
  92. package/src/observability/otel.js +2 -2
  93. package/src/protocols/mcp-client.js +6 -2
  94. package/src/protocols/mcp-server.js +191 -6
  95. package/src/protocols/transport/sse.js +23 -2
  96. package/tools/audit-docs.py +1 -1
  97. package/web-app/dist/assets/{AdminPage-D_e45uTw.js → AdminPage-DuRQZsF9.js} +1 -1
  98. package/web-app/dist/assets/{Avatar-T3nIpoaf.js → Avatar-7GtOQvsO.js} +1 -1
  99. package/web-app/dist/assets/{Badge-BKqb59pP.js → Badge-CYgTnIxj.js} +1 -1
  100. package/web-app/dist/assets/{Button-DjVlkh8_.js → Button-rYSyIu7X.js} +1 -1
  101. package/web-app/dist/assets/{CockpitPage-DXJgLGmh.js → CockpitPage-9adANY4o.js} +1 -1
  102. package/web-app/dist/assets/{ComparePage-BRP_eVc_.js → ComparePage-DEG2oA-R.js} +1 -1
  103. package/web-app/dist/assets/{ErrorBoundary-CLjpGLjC.js → ErrorBoundary-CwtvY4xs.js} +1 -1
  104. package/web-app/dist/assets/{EvidenceReceiptPanel-DX-vb4Xy.js → EvidenceReceiptPanel-DTT73pPB.js} +1 -1
  105. package/web-app/dist/assets/{GitHubIssuesPanel-214HVHtX.js → GitHubIssuesPanel-CpWZLz2x.js} +1 -1
  106. package/web-app/dist/assets/{GitHubPRsPanel-BEiZKc4t.js → GitHubPRsPanel-H293R7E2.js} +1 -1
  107. package/web-app/dist/assets/{HomePage-VvMHS5ga.js → HomePage-B11Imp9k.js} +2 -2
  108. package/web-app/dist/assets/{LoginPage-5WD-v7n3.js → LoginPage-BZBgx5Jr.js} +1 -1
  109. package/web-app/dist/assets/{MagicPage-DUQT_Jye.js → MagicPage-B27S4_X8.js} +1 -1
  110. package/web-app/dist/assets/{MetricsPage-lga-z79v.js → MetricsPage-CfbJWNDG.js} +1 -1
  111. package/web-app/dist/assets/{NotFoundPage-CGhBX3G1.js → NotFoundPage-Tp_4zMSm.js} +1 -1
  112. package/web-app/dist/assets/{ProjectPage-CdzF2GzZ.js → ProjectPage-CM4fgMsV.js} +3 -3
  113. package/web-app/dist/assets/{ProjectsPage-DRG64N8s.js → ProjectsPage-DP2Fvsrd.js} +1 -1
  114. package/web-app/dist/assets/{SettingsPage-5fzW9Frb.js → SettingsPage-C4G9-EAy.js} +1 -1
  115. package/web-app/dist/assets/{ShowcasePage-DrTdxO4y.js → ShowcasePage-Dj-n4dwu.js} +1 -1
  116. package/web-app/dist/assets/{SystemSettingsPage-C9Mqs6Rd.js → SystemSettingsPage-BqMLpuGt.js} +1 -1
  117. package/web-app/dist/assets/{TeamsPage-CUGPdSWo.js → TeamsPage-mIH8H96m.js} +1 -1
  118. package/web-app/dist/assets/{TemplatesPage-CNraDY0F.js → TemplatesPage-BagW-v4n.js} +1 -1
  119. package/web-app/dist/assets/{TerminalOutput-BIu_6Pea.js → TerminalOutput-CTQRHhnK.js} +1 -1
  120. package/web-app/dist/assets/{activity-Bk-kgqaf.js → activity-DNQiBDDL.js} +1 -1
  121. package/web-app/dist/assets/{bell-BXmUdmo8.js → bell-Coiwdad1.js} +1 -1
  122. package/web-app/dist/assets/{bot-CiuzXxUR.js → bot-Cou-rTgR.js} +1 -1
  123. package/web-app/dist/assets/{check-BEzjXppd.js → check-CsF-XtQp.js} +1 -1
  124. package/web-app/dist/assets/{chevron-left-AYWCXHf8.js → chevron-left-BJiy55Ht.js} +1 -1
  125. package/web-app/dist/assets/{circle-alert-BNg2uSRq.js → circle-alert-D6-pQQWq.js} +1 -1
  126. package/web-app/dist/assets/{clock-DTj0kkGT.js → clock-BOGqwgt9.js} +1 -1
  127. package/web-app/dist/assets/{cloud-x4nTDBLT.js → cloud-DsxhTtf5.js} +1 -1
  128. package/web-app/dist/assets/{code-xml-BVh_MLrk.js → code-xml-CxJDHUlE.js} +1 -1
  129. package/web-app/dist/assets/{database-DdfBaowG.js → database-BJePscl_.js} +1 -1
  130. package/web-app/dist/assets/{dollar-sign-XuYFmAOY.js → dollar-sign-6qWGAkZo.js} +1 -1
  131. package/web-app/dist/assets/{file-code-corner-D4cRnmeL.js → file-code-corner-DcOtYeDb.js} +1 -1
  132. package/web-app/dist/assets/{file-plus-CyoVlHc_.js → file-plus-WuRyLFo0.js} +1 -1
  133. package/web-app/dist/assets/{globe-Y6IK2RPW.js → globe-r-xCP4DE.js} +1 -1
  134. package/web-app/dist/assets/{hammer-BKzr9VZI.js → hammer-DTt0SsCB.js} +1 -1
  135. package/web-app/dist/assets/{index-B20cSx5G.js → index-BkbXyH8y.js} +3 -3
  136. package/web-app/dist/assets/{layers-DebNOhGS.js → layers-BvZhvSMY.js} +1 -1
  137. package/web-app/dist/assets/{loader-circle-DyGbrEgd.js → loader-circle-3gosTei9.js} +1 -1
  138. package/web-app/dist/assets/{lock-BKPpyt20.js → lock-CZZMxP0U.js} +1 -1
  139. package/web-app/dist/assets/{package-egF5Wi4y.js → package-C5A8CkJr.js} +1 -1
  140. package/web-app/dist/assets/{plus-OiEgKIc-.js → plus-Btv7tTIF.js} +1 -1
  141. package/web-app/dist/assets/{refresh-cw-CzKvrONq.js → refresh-cw-DsWLXgs_.js} +1 -1
  142. package/web-app/dist/assets/{rotate-ccw-Bu2mII0p.js → rotate-ccw-DOVDjway.js} +1 -1
  143. package/web-app/dist/assets/{scroll-text-CSkiyax8.js → scroll-text-smySzlrX.js} +1 -1
  144. package/web-app/dist/assets/{server-DlPthJFw.js → server-b5PHsqAU.js} +1 -1
  145. package/web-app/dist/assets/{shield-alert-CbpHWQQX.js → shield-alert-BD7FDlh-.js} +1 -1
  146. package/web-app/dist/assets/{thumbs-up-DgGpZe-Q.js → thumbs-up-CAsFzbyE.js} +1 -1
  147. package/web-app/dist/assets/{trash-2-BV3GlCB-.js → trash-2-BJ35qHgl.js} +1 -1
  148. package/web-app/dist/assets/{trending-down-Y4TJtXhD.js → trending-down-Ozrd26cZ.js} +1 -1
  149. package/web-app/dist/assets/{trending-up-DsDNoHZY.js → trending-up-BhnMcM32.js} +1 -1
  150. package/web-app/dist/assets/{upload-gkThrc_I.js → upload-JVHfdwoA.js} +1 -1
  151. package/web-app/dist/assets/{usePolling-jpNSeNAe.js → usePolling-CTzbDV-e.js} +1 -1
  152. package/web-app/dist/assets/{user-3Zez1WOK.js → user-Bks3-GYv.js} +1 -1
  153. package/web-app/dist/index.html +1 -1
  154. package/docs/ARCHITECTURE-OVERVIEW.md +0 -209
  155. package/docs/AUTONOMI-ECOSYSTEM.md +0 -107
  156. package/docs/COCKPIT-SPEC.md +0 -72
  157. package/docs/COCKPIT-UX-MANDATE.md +0 -53
  158. package/docs/COMPETITIVE-ANALYSIS.md +0 -303
  159. package/docs/COMPETITIVE-NEXT-10.md +0 -316
  160. package/docs/COMPETITIVE-RALPH-ZEROSHOT-2026-07-08.md +0 -81
  161. package/docs/DASHBOARD-9.12-EVIDENCE.md +0 -97
  162. package/docs/DASHBOARD-ARCHITECTURE.md +0 -425
  163. package/docs/DASHBOARD_V2_CHECKLIST.md +0 -243
  164. package/docs/DEMOS.md +0 -63
  165. package/docs/ENTERPRISE-IDENTITY-ROADMAP.md +0 -206
  166. package/docs/EVIDENCE-RECEIPT-BUILD-APPLICABILITY.md +0 -79
  167. package/docs/FEAT-PRDREUSE-DOCKER-PLAN.md +0 -144
  168. package/docs/GATE-FAILURE-TRIAGE.md +0 -254
  169. package/docs/HANDOFF-2026-08-03.md +0 -439
  170. package/docs/LOOP-CANDIDATE-PROPOSAL-v1.md +0 -167
  171. package/docs/LOOP-HARNESS-AUDIT.md +0 -684
  172. package/docs/MERGE-DEDUP-MAP.md +0 -420
  173. package/docs/MERGE-ROUTE-MAP.md +0 -139
  174. package/docs/MODEL-REGISTRY-PLAN.md +0 -155
  175. package/docs/OUTCOME-FRONTIER.md +0 -536
  176. package/docs/P2-SPEC-ROBUSTNESS-PLAN.md +0 -192
  177. package/docs/PLANS-INDEX.md +0 -32
  178. package/docs/PRD-REUSE-DONE-RECOGNITION-PLAN.md +0 -536
  179. package/docs/PROMPT-ABLATION-RESULT.md +0 -97
  180. package/docs/R4-TRUST-TRAJECTORY-DESIGN.md +0 -127
  181. package/docs/R5-AUTO-WIKI-DESIGN.md +0 -137
  182. package/docs/R6-ROLLBACK-CHECKPOINT-PLAN.md +0 -107
  183. package/docs/R7-ZERO-CONFIG-FIRST-RUN-PLAN.md +0 -137
  184. package/docs/R8-SHAREABLE-TEAM-ASSETS-PLAN.md +0 -129
  185. package/docs/R9-OPEN-CORE-HOOKS-PLAN.md +0 -113
  186. package/docs/RARV-C-100X-PLAN.md +0 -286
  187. package/docs/RARV-C-LOOP-EFFICIENCY-PLAN.md +0 -470
  188. package/docs/SHAREABLE-PROOF-PLAN.md +0 -194
  189. package/docs/SONNET5-DEFAULT-PLAN.md +0 -157
  190. package/docs/SPEED-AND-FIRST-PASS-PLAN.md +0 -281
  191. package/docs/STALE-STATE-AUDIT.md +0 -174
  192. package/docs/SYNERGY-TASKS.md +0 -143
  193. package/docs/TASKLIST-ACCURACY-PLAN.md +0 -355
  194. package/docs/TOP-100-BACKLOG.md +0 -159
  195. package/docs/V8-ACCEPTANCE-TRIAGE-2026-07-24.md +0 -114
  196. package/docs/V8-COMPLEXITY-AUDIT-2026-07-24.md +0 -45
  197. package/docs/V8-MAJOR-RELEASE-PLAN.md +0 -137
  198. package/docs/V8-OVERNIGHT-PLAN-2026-07-25.md +0 -82
  199. package/docs/V8-SDK-RESEARCH-RAW.md +0 -129
  200. package/docs/WELCOME-OPENER-PLAN.md +0 -106
  201. package/docs/adoption-baseline-2026-07-31.md +0 -84
  202. package/docs/architecture/bmad-integration-epic.md +0 -271
  203. package/docs/architecture/bmad-integration-review.md +0 -86
  204. package/docs/architecture/bmad-integration-validation.md +0 -249
  205. package/docs/architecture/bmad-loki-voice-agent-council-analysis.md +0 -61
  206. package/docs/auto-claude-comparison.md +0 -250
  207. package/docs/bug-fixes/agent-01-cli-fixes.md +0 -101
  208. package/docs/bug-fixes/agent-02-purplelab-fixes.md +0 -88
  209. package/docs/bug-fixes/agent-03-dashboard-fixes.md +0 -119
  210. package/docs/bug-fixes/agent-04-memory-fixes.md +0 -105
  211. package/docs/bug-fixes/agent-05-provider-fixes.md +0 -86
  212. package/docs/bug-fixes/agent-06-integration-fixes.md +0 -101
  213. package/docs/bug-fixes/agent-07-dash-run-fixes.md +0 -101
  214. package/docs/bug-fixes/agent-08-docker-fixes.md +0 -164
  215. package/docs/bug-fixes/agent-09-e2e-build-fixes.md +0 -69
  216. package/docs/bug-fixes/agent-10-e2e-fullstack-fixes.md +0 -102
  217. package/docs/bug-fixes/agent-11-e2e-session-fixes.md +0 -70
  218. package/docs/bug-fixes/agent-12-scenario-fixes.md +0 -120
  219. package/docs/bug-fixes/agent-13-enterprise-fixes.md +0 -143
  220. package/docs/bug-fixes/agent-14-uat-newuser-fixes.md +0 -88
  221. package/docs/bug-fixes/agent-15-uat-poweruser-fixes.md +0 -132
  222. package/docs/bug-fixes/agent-19-code-review.md +0 -316
  223. package/docs/bug-fixes/agent-20-architecture-review.md +0 -331
  224. package/docs/competitive/bolt-new-analysis.md +0 -579
  225. package/docs/competitive/emergence-others-analysis.md +0 -605
  226. package/docs/competitive/replit-lovable-analysis.md +0 -622
  227. package/docs/dashboard-guide.md +0 -487
  228. package/docs/enterprise/migration.md +0 -265
  229. package/docs/history/one-run-audit.md +0 -304
  230. package/docs/plans/FORGE-AUTONOMOUS-QUEUE.md +0 -312
  231. package/docs/plans/ULTRAPLAN-FORGE-BAAS.md +0 -612
  232. package/docs/plans/UT2-6-LSP-DIAGNOSTIC-BROADCAST.md +0 -394
  233. package/docs/prd-purple-lab-ide.md +0 -152
  234. package/docs/prd-purple-lab-platform-v2.md +0 -223
  235. package/docs/prd-purple-lab-platform.md +0 -319
  236. package/docs/retrospectives/v7.5.15-fleet-postmortem.md +0 -325
  237. package/docs/retrospectives/v7.5.15-honesty-audit.md +0 -136
  238. package/docs/retrospectives/v7.5.15-llm-failure-modes.md +0 -49
  239. package/docs/show-hn-post.md +0 -46
  240. package/docs/test-scenarios/enterprise-scenarios.md +0 -732
  241. package/docs/thick2thin.md +0 -173
  242. package/packages/control-plane/ui/dist/assets/index-DcBJXjCJ.js +0 -190
@@ -1,331 +0,0 @@
1
- # Agent 20: Architecture Review Report
2
-
3
- **Date:** 2026-03-24
4
- **Scope:** Systemic architecture issues, component boundaries, security, complexity
5
- **Files Reviewed:** 40+ files across all major subsystems
6
-
7
- ---
8
-
9
- ## Executive Summary
10
-
11
- Loki Mode's architecture follows a filesystem-as-IPC pattern where all components
12
- communicate through `.loki/` state files. While pragmatic for a CLI-first tool,
13
- this design has accumulated several systemic issues as the codebase scaled to
14
- 40,000+ lines across Bash, Python, and TypeScript. The most critical findings
15
- are: (1) three inconsistent LOKI_DIR resolution mechanisms within the dashboard
16
- package, (2) a dual event system where events are written to two different
17
- locations with different formats, (3) non-atomic JSON writes in `set_phase()`
18
- that can corrupt state under concurrent access, and (4) extreme file sizes
19
- that hinder maintainability.
20
-
21
- ---
22
-
23
- ## CRITICAL -- Bugs Found and Fixed
24
-
25
- ### BUG ARCH-001: Non-atomic JSON write in `set_phase()` (SEVERITY: HIGH)
26
-
27
- **File:** `autonomy/run.sh`, line 3254-3261
28
-
29
- The `set_phase()` function updates `.loki/state/orchestrator.json` using a
30
- direct read-then-write pattern without atomicity:
31
-
32
- ```python
33
- with open(sys.argv[1], 'r') as f:
34
- data = json.load(f)
35
- data['currentPhase'] = sys.argv[2]
36
- with open(sys.argv[1], 'w') as f: # <-- Non-atomic: truncates then writes
37
- json.dump(data, f, indent=2)
38
- ```
39
-
40
- If the process is killed (Ctrl+C, OOM) between truncation and write completion,
41
- `orchestrator.json` will be empty or contain partial JSON. The dashboard's
42
- `_safe_json_read()` handles corrupt reads gracefully, but the state is permanently
43
- lost until the next `write_dashboard_state()` call re-derives it.
44
-
45
- This is the same class of bug already fixed elsewhere (BUG-XC-004, BUG-ST-008)
46
- using temp-file-plus-rename. The fix pattern is already established in the codebase.
47
-
48
- **Impact:** State corruption on crash during phase transition. The dashboard
49
- and completion council may see stale or missing phase data.
50
-
51
- ### BUG ARCH-002: Three inconsistent LOKI_DIR resolution mechanisms (SEVERITY: HIGH)
52
-
53
- Within the `dashboard/` package, three different files resolve the `.loki/`
54
- directory path using three different mechanisms:
55
-
56
- | File | Env Var | Default | Resolution |
57
- |------|---------|---------|------------|
58
- | `dashboard/control.py:30` | `LOKI_DIR` | `.loki` (CWD-relative) | Static at import time |
59
- | `dashboard/api_v2.py:68` | `LOKI_DATA_DIR` | `~/.loki` (user home) | Static at import time |
60
- | `dashboard/server.py:1869` | `LOKI_DIR` | `.loki` then `~/.loki` | Dynamic 4-step resolution per call |
61
-
62
- This means:
63
- - `control.py` reads/writes state from CWD's `.loki/`
64
- - `api_v2.py` reads policies from `~/.loki/`
65
- - `server.py` dynamically resolves based on env, API override, CWD, or home
66
-
67
- The `api_v2.py` one is particularly problematic because it uses `LOKI_DATA_DIR`
68
- (not `LOKI_DIR`) and resolves at module import time to `~/.loki`, which is the
69
- global directory, not the project directory. If a user has per-project `.loki/`
70
- directories (the normal case), the policy endpoints in api_v2 will look in the
71
- wrong location.
72
-
73
- **Impact:** Policy endpoints may read from wrong directory. State written by
74
- `control.py` may not be visible to `server.py` if CWD differs from project
75
- directory at dashboard startup time.
76
-
77
- ### BUG ARCH-003: Dual event system with incompatible formats (SEVERITY: MEDIUM)
78
-
79
- The codebase has two parallel event systems:
80
-
81
- 1. **JSONL append log** (`run.sh` lines 893-966): Events appended to
82
- `.loki/events.jsonl` with format `{"timestamp":..., "type":..., "data":...}`
83
- - Used by `emit_event()` and `emit_event_json()` -- 28 call sites in run.sh
84
- - Consumed by: dashboard (reads JSONL), CLI (reads JSONL)
85
-
86
- 2. **File-per-event directory** (`events/bus.py`, `events/emit.sh`):
87
- Events written as individual JSON files to `.loki/events/pending/` with
88
- format `{"id":..., "type":..., "source":..., "timestamp":..., "payload":...}`
89
- - Used by `emit_event_pending()` -- separate call sites
90
- - Consumed by: EventBus subscribers, MCP server, state manager
91
-
92
- These two systems have different schemas, different consumers, and no bridge
93
- between them. Events emitted via `emit_event()` are invisible to the EventBus
94
- and vice versa. The `emit_event_pending()` function in run.sh (line 971) writes
95
- to the pending directory but most call sites still use the JSONL functions.
96
-
97
- **Impact:** Components subscribing to the EventBus miss events emitted to JSONL.
98
- Dashboard state pushes are based on file polling rather than events, adding
99
- unnecessary latency.
100
-
101
- ---
102
-
103
- ## Systemic Architecture Issues
104
-
105
- ### ISSUE 1: Extreme file sizes impair maintainability (SEVERITY: HIGH)
106
-
107
- | File | Lines | Functions | Concern |
108
- |------|-------|-----------|---------|
109
- | `autonomy/loki` | 20,300 | 130+ `cmd_*` functions | Single-file CLI with 130 subcommands |
110
- | `autonomy/run.sh` | 10,869 | 150+ functions | Orchestration engine |
111
- | `dashboard/server.py` | 5,244 | 121+ routes | Monolithic API server |
112
-
113
- The `loki` CLI has nearly doubled from the 10,820 lines documented in CLAUDE.md
114
- to 20,300 lines. At this size, bash's lack of namespacing means every function
115
- and variable is global. A naming collision between `cmd_test()` helpers and
116
- `cmd_report()` helpers is a constant risk.
117
-
118
- **Recommendation:** Split `autonomy/loki` by command group:
119
- - `autonomy/commands/start.sh` -- start/stop/pause/resume
120
- - `autonomy/commands/dashboard.sh` -- dashboard/web commands
121
- - `autonomy/commands/github.sh` -- github/import/issue commands
122
- - `autonomy/commands/memory.sh` -- memory subcommands
123
- - `autonomy/commands/config.sh` -- config/setup commands
124
- - Each file sources into the main `loki` dispatcher
125
-
126
- ### ISSUE 2: 79 inline `python3 -c` calls in run.sh (SEVERITY: MEDIUM)
127
-
128
- The orchestrator shell script (`run.sh`) contains 79 inline Python one-liners
129
- for JSON parsing, state manipulation, and data extraction. For example, reading
130
- a single field from `orchestrator.json` spawns a new Python process each time:
131
-
132
- ```bash
133
- current_phase=$(python3 -c "import json; print(json.load(open('.loki/state/orchestrator.json')).get('currentPhase', 'BOOTSTRAP'))" 2>/dev/null || echo "BOOTSTRAP")
134
- ```
135
-
136
- In `write_dashboard_state()` alone, there are 8+ separate `python3 -c` calls
137
- that each open, parse, and close the same JSON files. Each call has ~50ms
138
- startup overhead, making the dashboard state writer measurably slow.
139
-
140
- **Recommendation:** Create a single helper script
141
- `autonomy/json-helper.py` that accepts commands like
142
- `json-helper.py get orchestrator.json currentPhase BOOTSTRAP` and can batch
143
- multiple reads in one invocation. Or use `jq` consistently (already used in
144
- some places).
145
-
146
- ### ISSUE 3: Dashboard has two separate FastAPI apps (SEVERITY: MEDIUM)
147
-
148
- The dashboard package contains two independent FastAPI applications:
149
-
150
- 1. `dashboard/server.py` -- Main API with 121+ routes, SQLAlchemy DB, auth, WebSocket
151
- 2. `dashboard/control.py` -- Separate FastAPI app with its own CORS, models, routes
152
-
153
- Both define their own `CORSMiddleware` configurations (with slightly different
154
- wildcard policies -- control.py uses `allow_methods=["*"]` and `allow_headers=["*"]`
155
- while server.py restricts both). Both define their own status/health models.
156
- The control.py `app` is never mounted into server.py's `app`; it appears to be
157
- a legacy standalone server that was partially superseded by server.py.
158
-
159
- The `atomic_write_json` function from `control.py` is imported by `server.py`
160
- (line 55: `from .control import atomic_write_json`), but the rest of control.py's
161
- routes are unreachable when the dashboard is run via server.py.
162
-
163
- **Recommendation:** Either mount control.py's router into server.py, or extract
164
- `atomic_write_json` into a standalone utility module and deprecate the separate
165
- app.
166
-
167
- ### ISSUE 4: State manager (state/manager.py) is underutilized (SEVERITY: LOW)
168
-
169
- A proper `StateManager` class exists at `state/manager.py` (1,896 lines) with:
170
- - File-based caching with watchdog
171
- - Thread-safe operations with file locking
172
- - Event bus integration
173
- - Version vectors for conflict resolution
174
- - Subscription system
175
-
176
- However, only the MCP server uses it (`mcp/server.py:48`). The main orchestrator
177
- (`run.sh`) uses raw file I/O. The dashboard (`server.py`) uses its own
178
- `_safe_json_read()`. This means the architecture has a proper abstraction layer
179
- that is largely bypassed.
180
-
181
- **Recommendation:** Gradually migrate dashboard state reads to use StateManager.
182
- The shell-based orchestrator cannot use it directly (Python vs Bash boundary),
183
- but the Python components should converge on this single state access layer.
184
-
185
- ### ISSUE 5: No file locking on orchestrator.json writes (SEVERITY: MEDIUM)
186
-
187
- While `save_state()` (line 7938) uses atomic temp-file+mv for
188
- `autonomy-state.json`, and `control.py` uses `fcntl.flock` for atomic writes,
189
- the `set_phase()` function and multiple inline Python snippets write to
190
- `.loki/state/orchestrator.json` without any locking or atomicity.
191
-
192
- The `write_dashboard_state()` function (line 3272) reads from `orchestrator.json`
193
- at the same time that `set_phase()` might be writing to it. Since these run in
194
- the same process (run.sh), there is no parallelism risk in the normal case.
195
- However, during parallel mode (worktrees), multiple run.sh instances could
196
- write to the same orchestrator.json if they share a `.loki/` directory.
197
-
198
- **Impact:** Potential data corruption in parallel mode.
199
-
200
- ---
201
-
202
- ## Security Architecture Review
203
-
204
- ### Strengths
205
- - **Path traversal protection** in MCP server (`validate_path()` with symlink chain checking)
206
- - **PRD path validation** in control.py (blocks `..`, verifies file exists within allowed dirs)
207
- - **Provider name validation** prevents shell injection in loader.sh
208
- - **CORS restricted to localhost** by default (both server.py and control.py)
209
- - **OIDC/SSO support** with proper JWT validation (PyJWT + cryptography)
210
- - **Token-based auth** with role/scope hierarchy
211
- - **Rate limiting** on control and read endpoints
212
- - **Atomic writes** in many critical paths (BUG-XC-004, BUG-ST-008)
213
-
214
- ### Concerns
215
-
216
- 1. **CORS wildcard inconsistency** (LOW): `control.py` uses `allow_methods=["*"]`
217
- and `allow_headers=["*"]` while `server.py` restricts to specific methods/headers.
218
- If control.py routes are ever exposed, the broader CORS policy applies.
219
-
220
- 2. **subprocess.Popen in control.py** (LOW): The `start_session` endpoint
221
- (line 410) passes `request.provider` into a command-line argument list.
222
- This IS validated: `request.validate_provider()` is called at line 379
223
- and raises ValueError (caught at line 381) before the Popen call. The
224
- validation is correct. However, `validate_provider()` is a manual method
225
- call rather than a Pydantic `@field_validator`, so it could be bypassed
226
- if someone adds a new endpoint that creates a StartRequest without calling
227
- validate. Converting to a Pydantic validator would make this defense
228
- automatic.
229
-
230
- 3. **No auth on event bus** (LOW): Any process that can write to
231
- `.loki/events/pending/` can inject events. This is acceptable for
232
- local single-user use but should be noted for multi-tenant deployments.
233
-
234
- ---
235
-
236
- ## Component Boundary Analysis
237
-
238
- ### CLI (loki) to Orchestrator (run.sh)
239
-
240
- **Boundary:** Clean. CLI `exec`s run.sh as a subprocess (via `cmd_start()`),
241
- passing args via command-line flags. State handoff is filesystem-based.
242
-
243
- **Issue:** The CLI re-implements some orchestrator functionality (e.g., memory
244
- loading at `loki:274`, status file reading) rather than delegating to run.sh.
245
- This creates subtle divergence risk.
246
-
247
- ### Web Server (server.py) to CLI
248
-
249
- **Boundary:** Indirect via filesystem. The dashboard reads `.loki/` state files
250
- that the orchestrator writes. For control operations, `control.py` spawns
251
- run.sh via `subprocess.Popen`.
252
-
253
- **Issue:** The dashboard does NOT call the CLI (`loki` binary) -- it calls
254
- `run.sh` directly. This bypasses any CLI-level validation, setup, or event
255
- emission that `cmd_start()` performs.
256
-
257
- ### Dashboard API to Orchestrator
258
-
259
- **Boundary:** File-based polling. The orchestrator writes `dashboard-state.json`
260
- every iteration. The dashboard reads it via `_push_loki_state_loop()` (every 2s
261
- when running, 30s when idle) and pushes to WebSocket clients.
262
-
263
- **Issue:** This is polling-based, not event-driven. The event bus exists but is
264
- not used for this communication path. Adding event bus integration would reduce
265
- latency from 2s to near-instant.
266
-
267
- ### Memory System to Everything
268
-
269
- **Boundary:** Clean Python API via `memory/engine.py`. The shell orchestrator
270
- bridges to it via Python one-liners.
271
-
272
- **Issue:** The memory engine is initialized independently by each consumer
273
- (run.sh via inline Python, MCP server via its own import, dashboard indirectly
274
- via state files). There is no shared singleton across components, so memory
275
- operations from different components may see inconsistent state.
276
-
277
- ### MCP Server to Dashboard + Memory
278
-
279
- **Boundary:** MCP server uses StateManager for state access and direct memory
280
- imports. It has no dependency on the dashboard.
281
-
282
- **Issue:** MCP tools overlap significantly with dashboard API endpoints (task
283
- management, memory retrieval, state queries). There is no deduplication or
284
- shared implementation between `/api/tasks` and the MCP `loki_queue_*` tools.
285
-
286
- ### Event Bus to All Components
287
-
288
- **Boundary:** File-based pub/sub via `.loki/events/pending/`.
289
-
290
- **Issue:** As documented in BUG ARCH-003, the event bus is underutilized.
291
- The main orchestrator (run.sh) emits to JSONL, not the event bus. The
292
- dashboard does not consume events from either system for real-time updates;
293
- it polls `dashboard-state.json` instead.
294
-
295
- ---
296
-
297
- ## Recommendations Summary (Prioritized)
298
-
299
- | Priority | Issue | Effort | Impact |
300
- |----------|-------|--------|--------|
301
- | P0 | Fix non-atomic write in `set_phase()` | 15 min | Prevents state corruption |
302
- | P0 | Unify LOKI_DIR resolution in dashboard package | 30 min | Prevents policy lookups from wrong directory |
303
- | P1 | Consolidate dual event systems | 2-4 hours | Consistent event propagation |
304
- | P3 | Convert `validate_provider()` to Pydantic field_validator | 10 min | Defense-in-depth validation |
305
- | P2 | Split `autonomy/loki` into command modules | 1-2 days | Maintainability |
306
- | P2 | Replace inline `python3 -c` with helper script | 4 hours | Performance improvement |
307
- | P2 | Merge control.py routes into server.py | 2 hours | Eliminate duplicate FastAPI app |
308
- | P3 | Adopt StateManager in dashboard | 1 day | Consistent state access |
309
- | P3 | Connect event bus to dashboard WebSocket push | 4 hours | Real-time updates |
310
- | P3 | Standardize CORS configuration | 30 min | Security consistency |
311
-
312
- ---
313
-
314
- ## Feedback Loop Verification
315
-
316
- ### Loop 1: Self-review
317
- - All findings reference specific file paths and line numbers
318
- - Severity ratings consider both likelihood and impact
319
- - Recommendations are actionable with effort estimates
320
-
321
- ### Loop 2: Code verification
322
- - BUG ARCH-001: Confirmed by reading `run.sh:3254-3261` -- no temp file + mv pattern
323
- - BUG ARCH-002: Confirmed by reading `control.py:30`, `api_v2.py:68`, `server.py:1869`
324
- - BUG ARCH-003: Confirmed by comparing `emit_event()` at line 893 vs `emit_event_pending()` at line 971
325
- - File sizes confirmed via `wc -l` (loki=20,300, run.sh=10,869, server.py=5,244)
326
- - Python3 -c count confirmed via grep (79 occurrences)
327
-
328
- ### Loop 3: Priority validation
329
- - P0 items are data integrity issues that can cause silent corruption
330
- - P1 items are defense-in-depth security and consistency
331
- - P2/P3 items are maintainability and performance improvements